diff --git a/ionicons/alert.svg b/ionicons/alert.svg
new file mode 100644
index 0000000..f0c4e2c
--- /dev/null
+++ b/ionicons/alert.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/ionicons/arrow-up-c.svg b/ionicons/arrow-up-c.svg
new file mode 100644
index 0000000..b0398ed
--- /dev/null
+++ b/ionicons/arrow-up-c.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/ionicons/chatbox.svg b/ionicons/chatbox.svg
new file mode 100644
index 0000000..0c2a7e7
--- /dev/null
+++ b/ionicons/chatbox.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/ionicons/chatboxes.svg b/ionicons/chatboxes.svg
new file mode 100644
index 0000000..dba6e29
--- /dev/null
+++ b/ionicons/chatboxes.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/ionicons/chatbubble.svg b/ionicons/chatbubble.svg
new file mode 100644
index 0000000..5c3148f
--- /dev/null
+++ b/ionicons/chatbubble.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/ionicons/chatbubbles.svg b/ionicons/chatbubbles.svg
new file mode 100644
index 0000000..8cc5f34
--- /dev/null
+++ b/ionicons/chatbubbles.svg
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/ionicons/earth.svg b/ionicons/earth.svg
new file mode 100644
index 0000000..078e7f7
--- /dev/null
+++ b/ionicons/earth.svg
@@ -0,0 +1,44 @@
+
+
+
+
diff --git a/ionicons/eye-disabled.svg b/ionicons/eye-disabled.svg
new file mode 100644
index 0000000..7a270cb
--- /dev/null
+++ b/ionicons/eye-disabled.svg
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/ionicons/eye.svg b/ionicons/eye.svg
new file mode 100644
index 0000000..6b64633
--- /dev/null
+++ b/ionicons/eye.svg
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/ionicons/heart.svg b/ionicons/heart.svg
new file mode 100644
index 0000000..34aa83d
--- /dev/null
+++ b/ionicons/heart.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/ionicons/image.svg b/ionicons/image.svg
new file mode 100644
index 0000000..b33d4ea
--- /dev/null
+++ b/ionicons/image.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/ionicons/images.svg b/ionicons/images.svg
new file mode 100644
index 0000000..708c415
--- /dev/null
+++ b/ionicons/images.svg
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/ionicons/loop.svg b/ionicons/loop.svg
new file mode 100644
index 0000000..865781e
--- /dev/null
+++ b/ionicons/loop.svg
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/ionicons/paper-airplane.svg b/ionicons/paper-airplane.svg
new file mode 100644
index 0000000..fc5fb14
--- /dev/null
+++ b/ionicons/paper-airplane.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/ionicons/paperclip.svg b/ionicons/paperclip.svg
new file mode 100644
index 0000000..6c21efb
--- /dev/null
+++ b/ionicons/paperclip.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/ionicons/person-stalker.svg b/ionicons/person-stalker.svg
new file mode 100644
index 0000000..cc47173
--- /dev/null
+++ b/ionicons/person-stalker.svg
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/ionicons/person.svg b/ionicons/person.svg
new file mode 100644
index 0000000..0b305ce
--- /dev/null
+++ b/ionicons/person.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/ionicons/pin.svg b/ionicons/pin.svg
new file mode 100644
index 0000000..f68b9f6
--- /dev/null
+++ b/ionicons/pin.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/ionicons/pricetag.svg b/ionicons/pricetag.svg
new file mode 100644
index 0000000..21624e2
--- /dev/null
+++ b/ionicons/pricetag.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/ionicons/pricetags.svg b/ionicons/pricetags.svg
new file mode 100644
index 0000000..9294f0e
--- /dev/null
+++ b/ionicons/pricetags.svg
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/ionicons/refresh.svg b/ionicons/refresh.svg
new file mode 100644
index 0000000..1e2d80e
--- /dev/null
+++ b/ionicons/refresh.svg
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/ionicons/reply.svg b/ionicons/reply.svg
new file mode 100644
index 0000000..d08d582
--- /dev/null
+++ b/ionicons/reply.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/ionicons/share.svg b/ionicons/share.svg
new file mode 100644
index 0000000..0030b8a
--- /dev/null
+++ b/ionicons/share.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/ionicons/star.svg b/ionicons/star.svg
new file mode 100644
index 0000000..3c4b403
--- /dev/null
+++ b/ionicons/star.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/ionicons/trash-a.svg b/ionicons/trash-a.svg
new file mode 100644
index 0000000..ec2afc2
--- /dev/null
+++ b/ionicons/trash-a.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..ce25db0
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,42 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#include "saoriwindow.h"
+#include "saoriapplication.h"
+#include
+#include
+
+int main(int argc, char *argv[])
+{
+ SaoriApplication a(argc, argv);
+ QTranslator translator;
+ translator.load(":/lang/saori.qm");
+ a.installTranslator(&translator);
+
+ SaoriWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/saori.pro b/saori.pro
new file mode 100644
index 0000000..a16a457
--- /dev/null
+++ b/saori.pro
@@ -0,0 +1,55 @@
+#-------------------------------------------------
+#
+# Project created by QtCreator 2017-11-20T07:19:06
+#
+#-------------------------------------------------
+
+QT += core gui network
+
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
+
+TARGET = saori
+TEMPLATE = app
+
+# The following define makes your compiler emit warnings if you use
+# any feature of Qt which as been marked as deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if you use deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ main.cpp \
+ saoriwindow.cpp \
+ saoridon.cpp \
+ saoriview.cpp \
+ saoriaddaccountdialog.cpp \
+ saoriaccount.cpp \
+ saoriapplication.cpp
+
+HEADERS += \
+ saoriwindow.h \
+ saoridon.h \
+ saoriview.h \
+ saoriaddaccountdialog.h \
+ saoridef.h \
+ saoriaccount.h \
+ saoriapplication.h
+
+FORMS += \
+ saoriwindow.ui \
+ saoriview.ui \
+ saoriaddaccountdialog.ui
+
+TRANSLATIONS += \
+ saori_ja.ts
+
+RESOURCES += \
+ saori.qrc
+
+DISTFILES += \
+ saori_ja.ts
diff --git a/saori.qrc b/saori.qrc
new file mode 100644
index 0000000..fb65ba0
--- /dev/null
+++ b/saori.qrc
@@ -0,0 +1,30 @@
+
+
+
+ ionicons/heart.svg
+ ionicons/trash-a.svg
+ ionicons/paperclip.svg
+ ionicons/paper-airplane.svg
+ ionicons/chatboxes.svg
+ ionicons/images.svg
+ ionicons/image.svg
+ ionicons/earth.svg
+ ionicons/eye-disabled.svg
+ ionicons/eye.svg
+ ionicons/star.svg
+ ionicons/pricetags.svg
+ ionicons/pricetag.svg
+ ionicons/person.svg
+ ionicons/person-stalker.svg
+ ionicons/chatbubbles.svg
+ ionicons/alert.svg
+ ionicons/pin.svg
+ ionicons/refresh.svg
+ ionicons/loop.svg
+ ionicons/chatbox.svg
+ ionicons/arrow-up-c.svg
+ ionicons/chatbubble.svg
+ ionicons/share.svg
+ ionicons/reply.svg
+
+
diff --git a/saori_ja.ts b/saori_ja.ts
new file mode 100644
index 0000000..7e676a5
--- /dev/null
+++ b/saori_ja.ts
@@ -0,0 +1,203 @@
+
+
+
+
+ SaoriAddAccountDialog
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SaoriView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SaoriWindow
+
+
+
+
+
+
+
+
+ ファイル(&F)
+
+
+
+
+ 表示(&V)
+
+
+
+
+ 編集(&E)
+
+
+
+
+ ヘルプ(&H)
+
+
+
+
+ タイムラインリスト(&l)
+
+
+
+
+
+
+
+
+
+ リスト
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ アカウント
+
+
+
+
+ ホーム
+
+
+
+
+ ローカルタイムライン
+
+
+
+
+ 連合タイムライン
+
+
+
+
+ 通知
+
+
+
+
+ インスタンス
+
+
+
+
+ 情報
+
+
+
diff --git a/saoriaccount.cpp b/saoriaccount.cpp
new file mode 100644
index 0000000..201ba0f
--- /dev/null
+++ b/saoriaccount.cpp
@@ -0,0 +1,108 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#include "saoriaccount.h"
+#include "saoridef.h"
+
+SaoriAccount::SaoriAccount(const QString accountName, Saoridon *instance, const QString accsessToken, QObject *parent) : QObject(parent)
+{
+ m_name = accountName;
+ m_accessToken = accsessToken;
+ m_instance = instance;
+ getAccountInfomation();
+}
+
+const QString SaoriAccount::accessToken()
+{
+ return m_accessToken;
+}
+
+void SaoriAccount::setAccessToken(QString token)
+{
+ m_accessToken = token;
+ return;
+}
+
+const QString SaoriAccount::name()
+{
+ return m_name;
+}
+
+void SaoriAccount::setName(const QString name)
+{
+ m_name = name;
+ return;
+}
+
+Saoridon *SaoriAccount::instance()
+{
+ return m_instance;
+}
+
+void SaoriAccount::getAccountInfomation()
+{
+ auto manager = new QNetworkAccessManager();
+ QNetworkRequest request = createHearder();
+ request.setUrl(QUrl(m_instance->instance().url() + SAORI_MASTODON_APIPATH_ACCOUNTS + "/verify_credentials"));
+ auto *reply = manager->get(request);
+ connect(manager,&QNetworkAccessManager::finished,[=](){
+ if (reply->NoError == QNetworkReply::NoError) {
+ QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object();
+ QMap info;
+ for(auto it = json.begin();it != json.end();it ++) {
+ info[it.key()] = it.value().toString();
+ }
+ m_accountInfo = info;
+ emit accountInfomationChanged();
+ }
+ manager->deleteLater();
+ });
+ return;
+}
+
+QNetworkRequest SaoriAccount::createHearder()
+{
+ QNetworkRequest request;
+ request.setRawHeader("Authorization","Bearer " + accessToken().toLatin1());
+ return request;
+}
+
+const QString SaoriAccount::accountInfo(const QString key)
+{
+ return m_accountInfo[key];
+}
+
+const QStringList SaoriAccount::timelineList()
+{
+ QStringList tl;
+ tl << "home"
+ << "local"
+ << "public"
+ << "notifications"
+ ;
+ return tl;
+
+}
diff --git a/saoriaccount.h b/saoriaccount.h
new file mode 100644
index 0000000..6adbb17
--- /dev/null
+++ b/saoriaccount.h
@@ -0,0 +1,72 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#ifndef SAORIACCOUNT_H
+#define SAORIACCOUNT_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+class SaoriAccount : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName)
+ Q_PROPERTY(QString accessToken READ accessToken WRITE setAccessToken NOTIFY accessTokenChanged)
+
+public:
+ explicit SaoriAccount(const QString accountName, Saoridon *instance, const QString accsessToken, QObject *parent = nullptr);
+ const QString accessToken();
+ void setAccessToken(QString token);
+ const QString name();
+ void setName(const QString name);
+ Saoridon *instance();
+ const QString accountInfo(const QString key);
+ const QStringList timelineList();
+
+protected:
+ void getAccountInfomation();
+ QNetworkRequest createHearder();
+ void requestGET(QUrl url,QNetworkAccessManager *manager);
+
+protected:
+ QString m_name;
+ QString m_accessToken;
+ Saoridon *m_instance;
+ QMap m_accountInfo;
+
+signals:
+ void accessTokenChanged(QString);
+ void accountInfomationChanged();
+
+public slots:
+};
+
+#endif // SAORIACCOUNT_H
diff --git a/saoriaddaccountdialog.cpp b/saoriaddaccountdialog.cpp
new file mode 100644
index 0000000..828f04a
--- /dev/null
+++ b/saoriaddaccountdialog.cpp
@@ -0,0 +1,112 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#include "saoriaddaccountdialog.h"
+#include "saoriapplication.h"
+#include "saoridef.h"
+#include "ui_saoriaddaccountdialog.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+SaoriAddAccountDialog::SaoriAddAccountDialog(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::SaoriAddAccountDialog)
+{
+ ui->setupUi(this);
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ for(int i = 0;i < SaoriApplication::getInstanceList()->count();i ++) {
+ ui->instanceUrl_comboBox->addItem(SaoriApplication::getInstanceList()->at(i)->instance().toString());
+ }
+ ui->getAccessToken_pushButton->setEnabled(false);
+ ui->authorizeCode_lineEdit->setEnabled(false);
+ connect(ui->instanceUrl_comboBox,&QComboBox::editTextChanged,[this](QString) {
+ m_instance = SaoriApplication::findInstance(ui->instanceUrl_comboBox->currentText());
+ if (m_instance != nullptr) ui->openWebBrowser_pushButton->setEnabled(true);
+ else ui->openWebBrowser_pushButton->setEnabled(false);
+ });
+}
+
+SaoriAddAccountDialog::~SaoriAddAccountDialog()
+{
+ delete ui;
+}
+
+void SaoriAddAccountDialog::on_openWebBrowser_pushButton_clicked()
+{
+ m_instance = SaoriApplication::findInstance(ui->instanceUrl_comboBox->currentText());
+ if (m_instance == nullptr) return;
+ if (m_instance->clientId().isEmpty() || m_instance->clientSecret().isEmpty()) {
+ qDebug() << "regist";
+ }
+ QDesktopServices::openUrl(m_instance->getAuthorizedUrl());
+ QString text = ui->instanceUrl_comboBox->currentText();
+ ui->instanceUrl_comboBox->clear();
+ ui->instanceUrl_comboBox->addItem(text);
+ ui->instanceUrl_comboBox->setEditable(false);
+ ui->openWebBrowser_pushButton->setEnabled(false);
+ ui->getAccessToken_pushButton->setEnabled(true);
+ ui->authorizeCode_lineEdit->setEnabled(true);
+ return;
+}
+
+void SaoriAddAccountDialog::on_getAccessToken_pushButton_clicked()
+{
+ if (ui->authorizeCode_lineEdit->text().isEmpty()) return;
+ QString token = m_instance->getAccessToken(ui->authorizeCode_lineEdit->text());
+ if (token.isEmpty()) return;
+ m_account = new SaoriAccount("check",m_instance,token);
+
+ auto manager = new QNetworkAccessManager();
+ QEventLoop event;
+ connect(manager,&QNetworkAccessManager::finished,&event,&QEventLoop::quit);
+ QUrlQuery params;
+ QNetworkRequest request;
+ QString instance = m_instance->instanceInfo("uri");
+
+ request.setRawHeader("Authorization","Bearer " + token.toLatin1());
+ request.setUrl(QUrl(m_instance->instance().url() + SAORI_MASTODON_APIPATH_ACCOUNTS + "/verify_credentials"));
+ auto reply = manager->get(request);
+ event.exec();
+ if (reply->error() != QNetworkReply::NoError) {
+ manager->deleteLater();
+ return;
+ }
+ QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object();
+ QString account = json["acct"].toString();
+ manager->deleteLater();
+
+ m_account->setName(account + "@" + instance);
+ ui->account_lineEdit->setText(m_account->name());
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+ return;
+
+}
diff --git a/saoriaddaccountdialog.h b/saoriaddaccountdialog.h
new file mode 100644
index 0000000..ad5c13c
--- /dev/null
+++ b/saoriaddaccountdialog.h
@@ -0,0 +1,59 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#ifndef SAORIADDACCOUNTDIALOG_H
+#define SAORIADDACCOUNTDIALOG_H
+
+#include
+#include
+#include
+
+namespace Ui {
+class SaoriAddAccountDialog;
+}
+
+class SaoriAddAccountDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit SaoriAddAccountDialog(QWidget *parent = 0);
+ ~SaoriAddAccountDialog();
+
+public:
+ Saoridon *m_instance;
+ SaoriAccount *m_account;
+
+private slots:
+ void on_openWebBrowser_pushButton_clicked();
+
+ void on_getAccessToken_pushButton_clicked();
+
+private:
+ Ui::SaoriAddAccountDialog *ui;
+};
+
+#endif // SAORIADDACCOUNTDIALOG_H
diff --git a/saoriaddaccountdialog.ui b/saoriaddaccountdialog.ui
new file mode 100644
index 0000000..11d3d82
--- /dev/null
+++ b/saoriaddaccountdialog.ui
@@ -0,0 +1,154 @@
+
+
+ SaoriAddAccountDialog
+
+
+
+ 0
+ 0
+ 511
+ 272
+
+
+
+ Add new Account
+
+
+ -
+
+
-
+
+
+ Instance URL:
+
+
+
+ -
+
+
+ Get Access token:
+
+
+
+ -
+
+
+ Open Authorize page:
+
+
+
+ -
+
+
+ Authorize Code:
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Account:
+
+
+
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Check
+
+
+
+ -
+
+
+ Open WebBrowser
+
+
+
+ -
+
+
+ -
+
+
+ Get!
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+
+
+
+
+
+
+
+
+ buttonBox
+ accepted()
+ SaoriAddAccountDialog
+ accept()
+
+
+ 248
+ 254
+
+
+ 157
+ 274
+
+
+
+
+ buttonBox
+ rejected()
+ SaoriAddAccountDialog
+ reject()
+
+
+ 316
+ 260
+
+
+ 286
+ 274
+
+
+
+
+
diff --git a/saoriapplication.cpp b/saoriapplication.cpp
new file mode 100644
index 0000000..2fdd9d7
--- /dev/null
+++ b/saoriapplication.cpp
@@ -0,0 +1,149 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#include "saoriapplication.h"
+#include "saoridef.h"
+#include
+#include
+#include
+#include
+
+SaoriApplication *SaoriApplication::m_self = nullptr;
+
+SaoriApplication::SaoriApplication(int &argc, char **argv)
+ :QApplication(argc, argv, true)
+{
+ m_self = this;
+ setOrganizationName(SAORI_QSETTINGS_ORGANIZATION);
+ setOrganizationDomain(SAORI_QSETTINGS_DOMAIN);
+ setApplicationName(SAORI_QSETTINGS_APPLICATION);
+
+ m_config = new QSettings(SAORI_QSETTINGS_DOMAIN,SAORI_QSETTINGS_APPLICATION,this);
+
+ loadSettings();
+
+ QDir dir;
+ if (!dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))) {
+ // CacheLocation is not writable.
+ }
+}
+
+SaoriApplication::~SaoriApplication()
+{
+ saveInstancesSettings();
+ saveAccountsSettings();
+}
+
+Saoridon *SaoriApplication::findInstance(QUrl instance)
+{
+ for(int i = 0;i < getInstanceList()->count();i ++) {
+ if (getInstanceList()->at(i)->instance() == instance) return getInstanceList()->at(i);
+ break;
+ }
+ return nullptr;
+}
+
+SaoriAccount *SaoriApplication::findAccount(QString account)
+{
+ for(int i = 0;i < getAccountList()->count();i ++) {
+ if (getAccountList()->at(i)->name() == account) return getAccountList()->at(i);
+ break;
+ }
+ return nullptr;
+}
+
+QList *SaoriApplication::getInstanceList()
+{
+ return &m_self->m_instanceList;
+}
+
+QList *SaoriApplication::getAccountList()
+{
+ return &m_self->m_accountList;
+}
+
+SaoriApplication *SaoriApplication::saori()
+{
+ return m_self;
+}
+
+void SaoriApplication::loadSettings()
+{
+ m_config->beginGroup("instances");
+ auto instances = m_config->childGroups();
+ for(int i = 0;i < instances.count();i ++) {
+ m_config->beginGroup(instances[i]);
+ auto *instance = new Saoridon(m_config->value("url").toUrl(),this);
+ instance->setClientId(m_config->value("clientId").toString());
+ instance->setClientSecret(m_config->value("clientSecret").toString());
+ m_instanceList.append(instance);
+ m_config->endGroup();
+ }
+ m_config->endGroup();
+
+ m_config->beginGroup("accounts");
+ auto accounts = m_config->childGroups();
+ for(int i = 0;i < accounts.count();i ++) {
+ m_config->beginGroup(accounts[i]);
+ auto *account = new SaoriAccount(accounts[i],
+ findInstance(m_config->value("instance").toUrl()),
+ m_config->value("accessToken").toString(),
+ this);
+ m_accountList.append(account);
+ m_config->endGroup();
+ }
+ m_config->endGroup();
+
+}
+
+void SaoriApplication::saveInstancesSettings()
+{
+ m_config->remove("instances");
+ m_config->beginGroup("instances");
+ for(int i = 0;i < m_instanceList.count();i ++) {
+ m_config->beginGroup(QCryptographicHash::hash(m_instanceList[i]->instance().toString().toLatin1(),QCryptographicHash::Md5));
+ m_config->setValue("url",m_instanceList[i]->instance());
+ m_config->setValue("clientId",m_instanceList[i]->clientId());
+ m_config->setValue("clientSecret",m_instanceList[i]->clientSecret());
+ m_config->endGroup();
+ }
+ m_config->endGroup();
+ m_config->sync();
+}
+
+void SaoriApplication::saveAccountsSettings()
+{
+ m_config->remove("accounts");
+ m_config->beginGroup("accounts");
+ for(int i = 0;i < m_accountList.count();i ++) {
+ m_config->beginGroup(m_accountList[i]->name());
+ m_config->setValue("instance",m_accountList[i]->instance()->instance());
+ m_config->setValue("accessToken",m_accountList[i]->accessToken());
+ m_config->endGroup();
+ }
+ m_config->endGroup();
+ m_config->sync();
+}
diff --git a/saoriapplication.h b/saoriapplication.h
new file mode 100644
index 0000000..9d73de0
--- /dev/null
+++ b/saoriapplication.h
@@ -0,0 +1,65 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#ifndef SAORIAPPLICATION_H
+#define SAORIAPPLICATION_H
+
+#include
+#include
+#include
+#include
+#include
+
+class SaoriApplication : public QApplication
+{
+ Q_OBJECT
+public:
+ SaoriApplication(int &argc, char **argv);
+ ~SaoriApplication();
+ static Saoridon *findInstance(QUrl instance);
+ static SaoriAccount *findAccount(QString account);
+ static QList * getInstanceList();
+ static QList * getAccountList();
+ static SaoriApplication * saori();
+
+protected:
+ QSettings *m_config;
+ QList m_instanceList;
+ QList m_accountList;
+ static SaoriApplication *m_self;
+
+protected:
+ void loadSettings();
+ void saveInstancesSettings();
+ void saveAccountsSettings();
+
+public slots:
+
+signals:
+
+};
+
+#endif // SAORIAPPLICATION_H
diff --git a/saoridef.h b/saoridef.h
new file mode 100644
index 0000000..234bd60
--- /dev/null
+++ b/saoridef.h
@@ -0,0 +1,46 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#ifndef SAORIDEF_H
+#define SAORIDEF_H
+
+#define SAORI_CLIENT_NAME "Saori Mastodon Client"
+#define SAORI_CLIENT_REDIRECT_URI "urn:ietf:wg:oauth:2.0:oob"
+#define SAORI_CLIENT_SCOPES "read write follow"
+#define SAORI_CLIENT_WEBSITE "https://dev.net-p.org/tamra/saori/wiki"
+#define SAORI_QSETTINGS_ORGANIZATION "nop"
+#define SAORI_QSETTINGS_DOMAIN "net-p.org"
+#define SAORI_QSETTINGS_APPLICATION "Saori"
+
+#define SAORI_MASTODON_APIPATH_APPS "/api/v1/apps"
+#define SAORI_MASTODON_APIPATH_AUTHORIZE "/oauth/authorize"
+#define SAORI_MASTODON_APIPATH_TOKEN "/oauth/token"
+#define SAORI_MASTODON_APIPATH_INSTANCE "/api/v1/instance"
+#define SAORI_MASTODON_APIPATH_ACCOUNTS "/api/v1/accounts"
+#define SAORI_MASTODON_APIPATH_TIMELINE "/api/v1/timeline"
+
+
+#endif // SAORIDEF_H
diff --git a/saoridon.cpp b/saoridon.cpp
new file mode 100644
index 0000000..7a9f86b
--- /dev/null
+++ b/saoridon.cpp
@@ -0,0 +1,182 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#include "saoridon.h"
+#include "saoridef.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+Saoridon::Saoridon(QUrl instanceUrl,QObject *parent) : QObject(parent)
+{
+ setInstance(instanceUrl);
+ getInstanceInfomation();
+}
+
+const QUrl Saoridon::instance()
+{
+ return m_instance;
+}
+
+void Saoridon::setInstance(const QUrl instanceUrl)
+{
+ m_instance = instanceUrl;
+ return;
+}
+
+const QString Saoridon::clientId()
+{
+ return m_clientId;
+}
+
+void Saoridon::setClientId(const QString id)
+{
+ m_clientId = id;
+ return;
+}
+
+const QString Saoridon::clientSecret()
+{
+ return m_clientSecret;
+}
+
+void Saoridon::setClientSecret(const QString secret)
+{
+ m_clientSecret = secret;
+}
+
+bool Saoridon::clientRedistration()
+{
+ auto manager = new QNetworkAccessManager();
+ QEventLoop event;
+ connect(manager,SIGNAL(finished(QNetworkReply*)),&event,SLOT(quit()));
+ QUrlQuery params;
+ params.addQueryItem("client_name",SAORI_CLIENT_NAME);
+ params.addQueryItem("redirect_uris",SAORI_CLIENT_REDIRECT_URI);
+ params.addQueryItem("scopes",SAORI_CLIENT_SCOPES);
+ params.addQueryItem("website",SAORI_CLIENT_WEBSITE);
+ QNetworkRequest request;
+ request.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/x-www-form-urlencoded"));
+ request.setUrl(QUrl(instance().url() + SAORI_MASTODON_APIPATH_APPS));
+ auto *reply = manager->post(request,params.toString().toLatin1());
+ event.exec();
+ if (reply->error() != QNetworkReply::NoError) {
+ manager->deleteLater();
+ return false;
+ }
+ QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object();
+ QString id = json["client_id"].toString();
+ QString secret = json["client_secret"].toString();
+ if (id.isEmpty() || secret.isEmpty()) return false;
+ setClientId(id);
+ setClientSecret(secret);
+ manager->deleteLater();
+ return true;
+}
+
+const QUrl Saoridon::getAuthorizedUrl()
+{
+ //if (clientId().isEmpty() || clientSecret().isEmpty()) return QUrl();
+ QUrlQuery params;
+ params.addQueryItem("client_id",clientId());
+ params.addQueryItem("response_type","code");
+ params.addQueryItem("redirect_uri","urn:ietf:wg:oauth:2.0:oob");
+ params.addQueryItem("scope",SAORI_CLIENT_SCOPES);
+ QUrl url = instance().url() + SAORI_MASTODON_APIPATH_AUTHORIZE;
+ url.setQuery(params);
+ return url;
+
+
+
+}
+
+const QString Saoridon::getAccessToken(const QString code)
+{
+ auto manager = new QNetworkAccessManager();
+ QEventLoop event;
+ connect(manager,&QNetworkAccessManager::finished,&event,&QEventLoop::quit);
+ QUrlQuery params;
+ params.addQueryItem("grant_type","authorization_code");
+ params.addQueryItem("redirect_uri","urn:ietf:wg:oauth:2.0:oob");
+ params.addQueryItem("client_id",clientId());
+ params.addQueryItem("client_secret",clientSecret());
+ params.addQueryItem("code",code);
+ QNetworkRequest request;
+ request.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/x-www-form-urlencoded"));
+ request.setUrl(QUrl(instance().url() + SAORI_MASTODON_APIPATH_TOKEN));
+ auto *reply = manager->post(request,params.toString().toLatin1());
+ event.exec();
+ if (reply->error() != QNetworkReply::NoError) {
+ manager->deleteLater();
+ return QString();
+ }
+ QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object();
+ QString token = json["access_token"].toString();
+ manager->deleteLater();
+ return token;
+}
+
+void Saoridon::getInstanceInfomation()
+{
+ auto manager = new QNetworkAccessManager();
+ QNetworkRequest request;
+ request.setUrl(QUrl(instance().url() + SAORI_MASTODON_APIPATH_INSTANCE));
+ auto *reply = manager->get(request);
+ connect(manager,&QNetworkAccessManager::finished,[=](){
+ if (reply->NoError == QNetworkReply::NoError) {
+ QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object();
+ QMap info;
+ for (auto it = json.begin();it != json.end();it ++) {
+ info[it.key()] = it.value().toString();
+ }
+ m_instanceInfo = info;
+ emit instanceInfomationChanged();
+ }
+ manager->deleteLater();
+ });
+
+ m_timelineMap.clear();
+ m_timelineMap["home"] = QUrl(instance().url() + SAORI_MASTODON_APIPATH_TIMELINE + "/home");
+ m_timelineMap["local"] = QUrl(instance().url() + SAORI_MASTODON_APIPATH_TIMELINE + "/local");
+ m_timelineMap["public"] = QUrl(instance().url() + SAORI_MASTODON_APIPATH_TIMELINE + "/public");
+ m_timelineMap["notifications"] = QUrl(instance().url() + SAORI_MASTODON_APIPATH_TIMELINE + "/notifications");
+ return;
+}
+
+const QString Saoridon::instanceInfo(const QString key)
+{
+ return m_instanceInfo[key];
+}
+
+const QUrl Saoridon::timelineUrl(const QString timeline)
+{
+ return m_timelineMap[timeline];
+}
+
diff --git a/saoridon.h b/saoridon.h
new file mode 100644
index 0000000..6b23229
--- /dev/null
+++ b/saoridon.h
@@ -0,0 +1,74 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#ifndef SAORIDON_H
+#define SAORIDON_H
+
+#include
+#include
+#include
+
+class Saoridon : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl instance READ instance WRITE setInstance NOTIFY instanceChanged)
+ Q_PROPERTY(QString clientId READ clientId WRITE setClientId NOTIFY clientIdChanged)
+ Q_PROPERTY(QString clientSecret READ clientSecret WRITE setClientSecret NOTIFY clientSecretChanged)
+
+public:
+ Saoridon(QUrl instanceUrl,QObject *parent = nullptr);
+ const QUrl instance();
+ void setInstance(const QUrl instanceUrl);
+ const QString clientId();
+ void setClientId(const QString id);
+ const QString clientSecret();
+ void setClientSecret(const QString secret);
+ bool clientRedistration();
+ const QUrl getAuthorizedUrl();
+ const QString getAccessToken(const QString code);
+ const QString instanceInfo(const QString key);
+ const QUrl timelineUrl(const QString timeline);
+
+protected:
+ void getInstanceInfomation();
+
+protected:
+ QUrl m_instance;
+ QString m_clientId;
+ QString m_clientSecret;
+ QMap m_instanceInfo;
+ QMap m_timelineMap;
+
+signals:
+ void instanceChanged(QUrl);
+ void clientIdChanged(QString);
+ void clientSecretChanged(QString);
+ void instanceInfomationChanged();
+
+public slots:
+};
+
+#endif // SAORIDON_H
diff --git a/saoriview.cpp b/saoriview.cpp
new file mode 100644
index 0000000..9aa6d06
--- /dev/null
+++ b/saoriview.cpp
@@ -0,0 +1,60 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#include "saoriview.h"
+#include "ui_saoriview.h"
+#include
+
+QList SaoriView::m_viewList;
+
+SaoriView::SaoriView(const QString view, const QString account, QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::SaoriView)
+{
+ ui->setupUi(this);
+ m_viewname = view;
+ m_account = account;
+ m_viewList.append(this);
+}
+
+SaoriView::~SaoriView()
+{
+ delete ui;
+ m_viewList.removeOne(this);
+}
+
+SaoriView *SaoriView::findView(const QString view, const QString account)
+{
+ for(auto v:m_viewList) {
+ if ((v->m_viewname == view) && (v->m_account == account)) return v;
+ }
+ return nullptr;
+}
+
+void SaoriView::recived(QMap result)
+{
+ qDebug() << result;
+}
diff --git a/saoriview.h b/saoriview.h
new file mode 100644
index 0000000..2f793be
--- /dev/null
+++ b/saoriview.h
@@ -0,0 +1,58 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#ifndef SAORIVIEW_H
+#define SAORIVIEW_H
+
+#include
+#include
+
+namespace Ui {
+class SaoriView;
+}
+
+class SaoriView : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit SaoriView(const QString view,const QString account,QWidget *parent = 0);
+ ~SaoriView();
+ static SaoriView* findView(const QString view,const QString account);
+
+protected:
+ QString m_viewname;
+ QString m_account;
+ static QList m_viewList;
+
+public slots:
+ void recived(QMap result);
+
+private:
+ Ui::SaoriView *ui;
+};
+
+#endif // SAORIVIEW_H
diff --git a/saoriview.ui b/saoriview.ui
new file mode 100644
index 0000000..e4b2987
--- /dev/null
+++ b/saoriview.ui
@@ -0,0 +1,142 @@
+
+
+ SaoriView
+
+
+
+ 0
+ 0
+ 327
+ 368
+
+
+
+ Form
+
+
+ -
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 307
+ 316
+
+
+
+
+
+
+ -
+
+
+ 0
+
+
-
+
+
+ Pin
+
+
+
+ :/icons/ionicons/pin.svg:/icons/ionicons/pin.svg
+
+
+ true
+
+
+
+ -
+
+
+ Notify
+
+
+
+ :/icons/ionicons/alert.svg:/icons/ionicons/alert.svg
+
+
+ true
+
+
+
+ -
+
+
+ Auto reload
+
+
+
+ :/icons/ionicons/loop.svg:/icons/ionicons/loop.svg
+
+
+ true
+
+
+
+ -
+
+
+ Newest
+
+
+
+ :/icons/ionicons/arrow-up-c.svg:/icons/ionicons/arrow-up-c.svg
+
+
+
+ -
+
+
+ Reload
+
+
+
+ :/icons/ionicons/refresh.svg:/icons/ionicons/refresh.svg
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Toot
+
+
+
+ :/icons/ionicons/chatbox.svg:/icons/ionicons/chatbox.svg
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/saoriwindow.cpp b/saoriwindow.cpp
new file mode 100644
index 0000000..df44ea7
--- /dev/null
+++ b/saoriwindow.cpp
@@ -0,0 +1,130 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#include
+#include "saoriwindow.h"
+#include "ui_saoriwindow.h"
+#include "saoriapplication.h"
+#include "saoriaddaccountdialog.h"
+#include "saoriview.h"
+
+SaoriWindow::SaoriWindow(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::SaoriWindow)
+{
+ ui->setupUi(this);
+ connect(ui->actionAdd_Account,&QAction::triggered,this,&SaoriWindow::openAccountDialog);
+ updateTimelineList();
+}
+
+SaoriWindow::~SaoriWindow()
+{
+ delete ui;
+}
+
+void SaoriWindow::openView(const QStringList viewName)
+{
+ if (auto view = SaoriView::findView(viewName.at(1),viewName.at(0))) {
+ ui->mdiArea->setActiveSubWindow(qobject_cast(view->parent()));
+ return;
+ }
+ QString title = viewName.at(1) + ":" + viewName.at(0);
+ auto view = new SaoriView(viewName.at(1),viewName.at(0));
+ auto sub = ui->mdiArea->addSubWindow(view);
+ sub->setWindowTitle(title);
+ sub->show();
+}
+
+
+
+void SaoriWindow::openAccountDialog()
+{
+ auto dialog = new SaoriAddAccountDialog(this);
+ if (dialog->exec() == QDialog::Accepted) {
+ dialog->m_account->setParent(QApplication::instance());
+ SaoriApplication::getAccountList()->append(dialog->m_account);
+ }
+ delete dialog;
+}
+
+void SaoriWindow::updateTimelineList()
+{
+ ui->timelineTree->clear();
+ auto *accountItem = new QTreeWidgetItem(ui->timelineTree,QStringList() << tr("Accounts"));
+ accountItem->setIcon(0,QIcon(":/icons/ionicons/person-stalker.svg"));
+ for (int i = 0;i < SaoriApplication::getAccountList()->count();i ++) {
+ auto *item = new QTreeWidgetItem(accountItem,QStringList() << SaoriApplication::getAccountList()->at(i)->name());
+ item->setIcon(0,QIcon(":/icons/ionicons/person.svg"));
+ accountItem->addChild(item);
+ for (auto tl:SaoriApplication::getAccountList()->at(i)->timelineList()) {
+ // trick for translation.
+ QStringList trtl;
+ QString tlText,icon;
+ trtl << "home" << "local" << "public" << "notifications";
+ switch (trtl.indexOf(tl)) {
+ case 0:
+ tlText = tr("home");
+ icon = ":/icons/ionicons/chatbubbles.svg";
+ break;
+ case 1:
+ tlText = tr("local");
+ icon = ":/icons/ionicons/chatbubble.svg";
+ break;
+ case 2:
+ tlText = tr("public");
+ icon = ":/icons/ionicons/earth.svg";
+ break;
+ case 3:
+ tlText = tr("notifications");
+ icon = ":/icons/ionicons/alert.svg";
+ break;
+ default:
+ tlText = tl;
+ break;
+ }
+ auto tlItem = new QTreeWidgetItem(item,QStringList() << tlText
+ << SaoriApplication::getAccountList()->at(i)->name()
+ << tl);
+ if (!icon.isEmpty()) tlItem->setIcon(0,QIcon(icon));
+ item->addChild(tlItem);
+ }
+ }
+ auto *instanceItem = new QTreeWidgetItem(ui->timelineTree,QStringList() << tr("Instances"));
+ for (int i = 0;i < SaoriApplication::getInstanceList()->count();i ++) {
+ auto *item = new QTreeWidgetItem(instanceItem,QStringList() << SaoriApplication::getInstanceList()->at(i)->instance().toString());
+ instanceItem->addChild(item);
+ item->addChild(new QTreeWidgetItem(item,QStringList() << tr("Infomation")));
+ }
+}
+
+void SaoriWindow::on_timelineTree_itemDoubleClicked(QTreeWidgetItem *item, int)
+{
+ auto account = SaoriApplication::findAccount(item->text(1));
+ if (account) {
+ qDebug() << account->instance()->timelineUrl(item->text(2));
+ openView(QStringList() << item->text(1) << item->text(2));
+ }
+}
diff --git a/saoriwindow.h b/saoriwindow.h
new file mode 100644
index 0000000..58587ea
--- /dev/null
+++ b/saoriwindow.h
@@ -0,0 +1,61 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#ifndef SAORIWINDOW_H
+#define SAORIWINDOW_H
+
+#include
+#include
+
+namespace Ui {
+class SaoriWindow;
+}
+
+class SaoriWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit SaoriWindow(QWidget *parent = 0);
+ ~SaoriWindow();
+
+protected:
+ void openView(const QStringList viewName);
+
+protected slots:
+ void openAccountDialog();
+ void updateTimelineList();
+
+protected:
+
+private slots:
+ void on_timelineTree_itemDoubleClicked(QTreeWidgetItem *item, int);
+
+private:
+ Ui::SaoriWindow *ui;
+};
+
+#endif // SAORIWINDOW_H
diff --git a/saoriwindow.ui b/saoriwindow.ui
new file mode 100644
index 0000000..dff0541
--- /dev/null
+++ b/saoriwindow.ui
@@ -0,0 +1,247 @@
+
+
+ SaoriWindow
+
+
+
+ 0
+ 0
+ 768
+ 628
+
+
+
+ Saori
+
+
+ false
+
+
+ QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks
+
+
+
+ -
+
+
+ QMdiArea::SubWindowView
+
+
+ false
+
+
+ true
+
+
+ QTabWidget::Rounded
+
+
+ QTabWidget::North
+
+
+
+
+
+
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ QDockWidget::NoDockWidgetFeatures
+
+
+ Qt::LeftDockWidgetArea
+
+
+ Timeline &list
+
+
+ 1
+
+
+
+ false
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Auto reload Interval (minutes)
+
+
+
+ -
+
+
+ -
+
+
+ Qt::DefaultContextMenu
+
+
+
+ List
+
+
+
-
+
+ Account
+
+
+ -
+
+ Instance
+
+
+
+
+
+
+
+
+
+ &Quit
+
+
+
+
+ true
+
+
+ true
+
+
+ Show/Hide Timeline &List
+
+
+
+
+ &Open Timeline
+
+
+
+
+ &Add Account
+
+
+
+
+ &Remove Account
+
+
+
+
+ true
+
+
+ &TabbedView mode
+
+
+
+
+ T&iled
+
+
+
+
+
+
+
+ actionShow_Hide_Timeline_List
+ triggered(bool)
+ dockWidget
+ setVisible(bool)
+
+
+ -1
+ -1
+
+
+ 136
+ 338
+
+
+
+
+ actionTiled
+ triggered()
+ mdiArea
+ tileSubWindows()
+
+
+ -1
+ -1
+
+
+ 521
+ 322
+
+
+
+
+