Compare commits

..

31 Commits

Author SHA1 Message Date
6982a97d22 修改: src/downloadlist.cpp 2021-12-13 20:12:21 +08:00
1ba01588f0 修改: debian/DEBIAN/control
新文件:   debian/opt/durapps/spark-store/bin/spark-dstore-patch
2021-12-13 20:07:33 +08:00
4a7f9f7500 修改: build.sh
新文件:   spark-dstore-patch
2021-12-11 23:28:58 +08:00
47690ee666 修改: debian/DEBIAN/triggers
修改:     debian/opt/durapps/spark-store/bin/spark-store
2021-12-11 23:23:33 +08:00
3477d50689 修改: debian/DEBIAN/control
修改:     debian/opt/durapps/spark-store/bin/spark-store
	修改:     debian/usr/share/spark-store/translations/spark-store_zh_CN.qm
	修改:     src/main.cpp
	修改:     src/widget.cpp
2021-12-11 23:18:40 +08:00
abf1e0df71 add debian/DEBIAN/triggers. 2021-12-11 09:52:54 +00:00
1ac033e850 update debian/DEBIAN/postrm. 2021-12-11 09:52:30 +00:00
c2d9b0324a update debian/DEBIAN/postinst. 2021-12-11 09:52:17 +00:00
5727b54c3f update debian/DEBIAN/control. 2021-12-11 09:52:04 +00:00
d796d296c0 update build.sh. 2021-11-24 20:37:42 +00:00
31ecde133e update debian/DEBIAN/control. 2021-10-26 12:02:41 +00:00
d6d40d2b78 修改: debian/usr/share/spark-store/translations/spark-store_zh_CN.qm
修改:     src/widget.ui
	修改:     translations/spark-store_zh_CN.qm
	修改:     translations/spark-store_zh_CN.ts
2021-10-24 23:46:36 +08:00
ed220702b3 修改: debian/DEBIAN/control
修改:     debian/opt/durapps/spark-store/bin/spark-store
	修改:     debian/usr/share/spark-store/translations/spark-store_zh_CN.qm
	修改:     translations/spark-store_zh_CN.qm
	修改:     translations/spark-store_zh_CN.ts
2021-10-24 22:55:00 +08:00
RigoLigoRLC
bdef388b2e 去除翻译功能,改为催更 2021-10-24 00:46:50 +08:00
a31a36dbd8 chore: 允许应用详情页复制文字 2021-07-15 16:39:27 +08:00
f23809b28e fix: 修复软件包卸载问题
fix: 修复软件包卸载失败以及取消卸载后显示成功的问题
fix: 修复下载列表不显示应用缩略图的问题
chore: 优化部分代码
2021-07-15 16:07:14 +08:00
7d4944279f !24 更新了投稿链接
Merge pull request !24 from momen/master
2021-07-01 03:46:58 +00:00
3dfca9a17d 更新打包文件以及 README.md 2021-06-30 14:37:38 +08:00
9b189f276e chore: 尝试开启 Hidpi 支持 2021-06-30 14:24:22 +08:00
51518e4e88 chore: 支持从源列表文件动态获取镜像源
支持从源列表文件动态获取镜像源,获取失败时默认只使用 d.store.deepinos.org.cn 该地址;

修复之前版本中设置界面“更新源”按钮无效的问题。
2021-06-30 14:14:06 +08:00
zty199
961d174bf7 chore: 尝试添加打包脚本
尝试添加了自动编译打包脚本,由于不会使用 dh_make 故每次需要手动更新打包信息。
2021-06-29 21:52:41 +08:00
10b758d8f3 fix: 尝试修复详情页经常加载失败的问题
关闭传输超时上限,未下载完成则持续等待;可能存在严重问题......
2021-06-29 14:05:01 +08:00
78c5d31a29 Update Translations 2021-06-29 13:50:07 +08:00
adf8b478a8 chore: 修复投递链接;新增应用升级判断
fix: 修复投递链接;
chore: 应用详情页支持判断是否需要升级。
2021-06-29 13:46:26 +08:00
momen
1c748219f8 update README.md.
更新了投稿页面
2021-06-26 10:04:48 +00:00
shenmo
9def55a2c2 roll back: src/downloadlist.cpp 2021-06-21 16:27:07 +08:00
shenmo
cd1892fd66 修改: src/downloadlist.cpp
修改:     src/downloadlist.h
2021-06-21 16:22:23 +08:00
Jerry
83e2302cf8 !23 改 jenkinsfile
Merge pull request !23 from Jerry/N/A
2021-06-21 15:56:35 +08:00
Jerry
4deaf28659 改 jenkinsfile 2021-06-21 15:56:21 +08:00
shenmo
04d6174875 . 2021-06-21 14:13:22 +08:00
shenmo
0d64bff7fa 改版本号,传统艺能 2021-06-18 14:58:52 +08:00
224 changed files with 10658 additions and 11637 deletions

View File

@@ -1,143 +0,0 @@
cmake_minimum_required(VERSION 3.10)
project(spark_store)
set(EXECUTABLE_NAME spark-store)
# Begin Compilation Options
# When set to ON, DTK Plugin for DDE platform will be built.
# Note that only machines with DTK and dev packages installed can build the plugin.
set(SPARK_BUILD_DTK_PLUGIN ON)
# When set to ON, store will transmit telemetry even in Debug builds.
set(SPARK_FORCE_TELEMETRY OFF)
# End Compilation Options
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
#set(CMAKE_AUTOUIC ON)
set(QT_VERSION 5)
set(REQUIRED_LIBS
Core
Gui
Widgets
Network
Concurrent
LinguistTools)
set(REQUIRED_LIBS_QUALIFIED
Qt5::Core
Qt5::Gui
Qt5::Widgets
Qt5::Network
Qt5::Concurrent)
include_directories(inc)
include_directories(plugin)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(PRE_CONFIGURE_FILE "src/gitver.cpp.in")
set(POST_CONFIGURE_FILE "${CMAKE_CURRENT_BINARY_DIR}/src/gitver.cpp")
include(cmake/git_watcher.cmake)
add_library(gitver STATIC ${POST_CONFIGURE_FILE})
#target_include_directories(gitver PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
add_dependencies(gitver check_git)
set(SOURCE_FILES
src/main.cpp
resource/resource.qrc
gui/page/ui/settings.ui
gui/page/ui/homepage.ui
${WRAPPED_UI_FILES}
inc/gitver.h
inc/deepinplatform.h
inc/dtk/spkdtkplugin.h
inc/spkutils.h src/spkutils.cpp
inc/telemetry/collectid.h
inc/spkqsshelper.h gui/spkqsshelper.cpp
inc/qt/elidedlabel.h gui/qt/elidedlabel.cpp
inc/spkwindow.h gui/spkwindow.cpp
inc/spktitlebar.h gui/spktitlebar.cpp
inc/spkiconbutton.h gui/spkiconbutton.cpp
inc/spkui_general.h gui/spkui_general.cpp
inc/spkmainwindow.h gui/spkmainwindow.cpp
inc/spkmsgbox.h gui/spkmsgbox.cpp
inc/spkdialog.h gui/spkdialog.cpp
inc/spkabout.h gui/spkabout.cpp
inc/spkloading.h gui/spkloading.cpp
inc/spksidebartree.h gui/spksidebartree.cpp
inc/spkappitem.h gui/spkappitem.cpp
inc/spkdownloadentry.h gui/spkdownloadentry.cpp
inc/spkpopup.h gui/spkpopup.cpp
inc/spkstretchlayout.h gui/spkstretchlayout.cpp
inc/spkfocuslineedit.h
inc/spknotifydot.h gui/spknotifydot.cpp
inc/spkimgviewer.h gui/spkimgviewer.cpp
inc/page/spkpagebase.h gui/page/spkpagebase.cpp
inc/page/spkpagehome.h gui/page/spkpagehome.cpp
inc/page/spkpageuitest.h gui/page/spkpageuitest.cpp
inc/page/spkpageapplist.h gui/page/spkpageapplist.cpp
inc/page/spkpageappdetails.h gui/page/spkpageappdetails.cpp
inc/page/spkpagedownloads.h gui/page/spkpagedownloads.cpp
inc/page/spkpagesettings.h gui/page/spkpagesettings.cpp
inc/pkgs/spkpkgmgrbase.h
inc/pkgs/spkpkgmgrpacman.h src/pkgs/spkpkgmgrpacman.cpp
inc/pkgs/spkpkgmgrapt.h src/pkgs/spkpkgmgrapt.cpp
inc/spkstore.h src/spkstore.cpp
inc/spkuimsg.h src/spkuimsg.cpp
inc/spklogging.h src/spklogging.cpp
inc/spkresource.h src/spkresource.cpp
inc/spkdownload.h src/spkdownload.cpp
inc/spkconfig.h src/spkconfig.cpp
)
include(cmake/FindLibNotify.cmake)
include(cmake/FindGlib.cmake)
include(cmake/FindGdk3.cmake)
include_directories(${GLIB_INCLUDE_DIRS})
include_directories(${GDK3_INCLUDE_DIRS})
set(LIBLINKING ${LIBLINKING}
gitver
${LIBNOTIFY_LIBRARIES}
${GLIB_LIBRARIES}
${GDK3_LIBRARIES}
${CMAKE_DL_LIBS})
# Required for a good backtrace
add_compile_options(-g)
add_link_options(-rdynamic)
# Find Qt before adding other build targets
find_package(Qt${QT_VERSION} COMPONENTS ${REQUIRED_LIBS} REQUIRED)
QT5_WRAP_UI(WRAPPED_UI_FILES
gui/page/ui/settings.ui
gui/page/ui/homepage.ui)
add_custom_target(run_lupdate
COMMAND lupdate . -ts lang/zh.ts
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
qt5_add_translation(QM_FILES lang/zh.ts)
add_executable(${EXECUTABLE_NAME} ${SOURCE_FILES} ${QM_FILES})
if(SPARK_BUILD_DTK_PLUGIN)
add_subdirectory(plugin/dtkplugin)
add_dependencies(${EXECUTABLE_NAME} spkdtkplugin)
endif()
target_link_libraries(${EXECUTABLE_NAME} ${REQUIRED_LIBS_QUALIFIED} ${LIBLINKING})
install(TARGETS ${EXECUTABLE_NAME} RUNTIME DESTINATION bin)

6
Jenkinsfile vendored
View File

@@ -4,12 +4,12 @@ pipeline {
stage('build') {
agent {
docker {
image 'jerry979/dtke:5.11'
image 'jerry979/dtke:5.11.1'
}
}
steps {
sh 'mkdir build && cd build && cmake .. && make -j'
sh 'mkdir build && cd build && qmake .. && make '
archiveArtifacts(artifacts: 'build/src/spark-store', allowEmptyArchive: true, defaultExcludes: true)
}
}
@@ -30,4 +30,4 @@ pipeline {
}
}
}
}

325
README.md
View File

@@ -11,7 +11,7 @@
希望看到这里的人也可以加入我们的队伍开发或者投递应用都很欢迎共同构建Linux应用生态
### [在这里投稿](http://upload.spark-app.store)
### [在这里投稿](https://upload.deepinos.org/index)
web页面部分正在开发当中详情请见[web仓库](https://gitee.com/deepin-community-store/DCSAPP_WEB)
@@ -58,16 +58,331 @@ https://store.deepinos.org.cn/
Deepin V20/UOS 系统下, 安装依赖
```shell
sudo apt install qt5-default libdtkcore-dev libdtkwidget-dev qtwebengine5-dev libnotify-dev
sudo apt install qt5-default libdtkcore-dev libdtkgui-dev libdtkwidget-dev qtwebengine5-dev libnotify-dev
```
```shell
git clone https://gitee.com/deepin-community-store/spark-store.git
cd spark-store
mkdir build
cd build
mkdir build && cd build
qmake ..
make -j
```
./build文件下的spark-store即为可执行文件
./build 文件下的 spark-store 即为可执行文件
P.S. 安装依赖后直接运行 build.sh 即可编译并打包
# 星火应用商店文档
# 目录结构
几个目录结构
```
/
/icons 图标文件夹
/tags 首页图标
/tras 多语言翻译
```
主要的文件分析
```js
spark-store.pro Qt工程配置文件
ssinstall 调用包安装器的脚本
icons.qrc 图标资源文件
main.cpp 入口文件
widget.h widget.cpp widget.ui 主要窗口控件
downloadlist.h downloadlist.cpp downloadlist.ui 单个软件的下载安装展示控件
progressload.h progressload.cpp 网页加载显示 得在deepin上编译运行才能搞清楚
workerthreads.h workerthreads.cpp 应用信息加载线程
image_show.h image_show.cpp 应用页面截图预览控件
big_image.h big_image.cpp 大图查看控件
```
# 使用的开源库及第三方工具
* GDebi 一个 Ubuntu 软件中心的轻量级替代品 https://linux.cn/article-4982-1.html
* libnotify 系统通知 https://developer.gnome.org/libnotify/unstable/
# 源码分析
## 应用的组成部分
左侧应用分类菜单
主窗口的下拉菜单
应用列表页面
应用详情页面
应用首页,有几个链接跳转
商店设置页面
下载列表页面
## 应用初始化,及主控件加载
初始化 `DApplication` 进入事件循环。
设置关于我们弹窗 `DAboutDialog`
主控件 Widget 根据不同屏幕大小自适应。
首页打开webview页面如果传入了`spk://`参数,会打开应用详情页。
```cpp
// main.cpp
QString arg1=argv[1];
if(arg1.left(6)=="spk://"){
w.openUrl(QUrl(argv[1]));
}
// widget.cpp
void Widget::openUrl(QUrl u)
{
QString app=serverUrl + "store"+u.path()+"/app.json";
ui->webEngineView->setUrl(app); // 会触发 webEngineView 的
}
```
## Tags处理方式
**Tags处理方式**
```cpp
// widget.cpp
QString tags=json["Tags"].toString(); //Read the Tags
QStringList tagList=tags.split(";");
for (int i=0;i<tagList.size();i++) {
if(tagList[i]=="community")
ui->tag_community->show();//Tags icon shows like this
if(tagList[i]=="ubuntu")
ui->tag_ubuntu->show();
if(tagList[i]=="deepin")
ui->tag_deepin->show();
if(tagList[i]=="uos")
ui->tag_uos->show();
if(tagList[i]=="dtk5")
ui->tag_dtk5->show();
if(tagList[i]=="dwine2")
ui->tag_dwine2->show();
if(tagList[i]=="dwine5")
ui->tag_dwine5->show();
if(tagList[i]=="a2d")
ui->tag_a2d->show();
}
```
**Widget 初始化**
```cpp
void Widget::initConfig()
{
...
// 读取服务器URL并初始化菜单项的链接
QSettings readConfig(QDir::homePath()+"/.config/spark-store/config.ini",QSettings::IniFormat);
if(readConfig.value("server/choose").toString()!=""){
ui->comboBox_server->setCurrentText(readConfig.value("server/choose").toString());
appinfoLoadThread.setServer(serverUrl=readConfig.value("server/choose").toString());
}else {
appinfoLoadThread.setServer(serverUrl="http://sucdn.jerrywang.top/"); // 默认URL
}
configCanSave=true; // 防止触发保存配置信号
menuUrl[0]=serverUrl + "store/#/"; // 首页
// 下面是各个应用分类页面直接加载的webview的
// 每个连接对应一个左侧的菜单项,在构造函数用连接到 chooseLeftMenu 槽函数
menuUrl[1]=serverUrl + "store/#/network";
...
menuUrl[12]=serverUrl + "store/#/others";
...
ui->webfoot->hide();
//初始化首页
ui->webEngineView->setUrl(menuUrl[0]);
}
/**
* 菜单切换逻辑
*
*/
void Widget::chooseLeftMenu(int index)
{
nowMenu=index;
updateUI();
left_list[index]->setStyleSheet("color:#FFFFFF;background-color:"+main_color.name()+";border-radius:8;border:0px");
// index <=12 加载某个分类的应用列表的webviejw
// index == 13 加载下载列表页面
if(index<=12){
if(themeIsDark){
darkurl = URL
ui->webEngineView->setUrl(darkurl);
}else {
ui->webEngineView->setUrl(menuUrl[index]);
}
ui->stackedWidget->setCurrentIndex(0);
}else if (index==13) {
ui->stackedWidget->setCurrentIndex(1);
}
}
```
## 应用下载安装卸载分析
**应用详情页面加载**
```cpp
/**
* 加载单个应用的信息
*/
void Widget::on_webEngineView_urlChanged(const QUrl &arg1)
{
//分析出服务器中的分类名称
...
//如果是app.json就打开详情页
if(arg1.path().right(8)=="app.json"){
...
// 读取相应的应用信息
appinfoLoadThread.requestInterruption();
appinfoLoadThread.wait(100);
appinfoLoadThread.setUrl(arg1);
appinfoLoadThread.start();
}
}
// 设置详情页的APP信息
SpkAppInfoLoaderThread::requestSetAppInformation() -> Widget::sltAppinfoDetails()
// 设置详情页的APP图标
SpkAppInfoLoaderThread::finishedIconLoad() -> Widget::sltAppinfoIcon()
// 设置详情页的APP截图
SpkAppInfoLoaderThread::finishedScreenshotLoad() -> Widget::sltAppinfoScreenshot()
// 下载APP详情信息线程
void SpkAppInfoLoaderThread::run()
{
QProcess get_json;
get_json.start("curl -o app.json " + targetUrl.toString());
QFile app_json("app.json");
app.json
}
```
**应用下载**
Widget::on_pushButton_download_clicked() 是点击下载的安装方法。
最终使用的是 `QNetwrokAccessManager` 进行GET请求获取数据写入文件。
```cpp
void Widget::on_pushButton_download_clicked()
{
if(!isBusy){
file = new QFile(fileName);
...
nowDownload+=1;
startRequest(urList.at(nowDownload-1)); // 进行链接请求
}
}
void Widget::startRequest(QUrl url)
{
reply = manager->get(QNetworkRequest(url));
// 请求响应完成,关闭文件,清理下载队列
connect(reply,SIGNAL(finished()),this,SLOT(httpFinished()));
// 接收应用下载数据
connect(reply,SIGNAL(readyRead()),this,SLOT(httpReadyRead()));
// 更新应用下载进度
connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(updateDataReadProgress(qint64,qint64)));
}
```
使用 QSettings 来读取配置,更换服务源
```cpp
void Widget::on_comboBox_server_currentIndexChanged(const QString &arg1)
{
appinfoLoadThread.setServer(arg1); // 服务器信息更新
if(configCanSave){
ui->label_setting1->show();
QSettings *setConfig=new QSettings(QDir::homePath()+"/.config/spark-store/config.ini",QSettings::IniFormat);
setConfig->setValue("server/choose",arg1);
}
}
```
使用 `QProcess` 来调用各种小文件下载、包安装卸载的命令。
**应用安装**
```cpp
void Widget::httpFinished() // 完成下载
{
...
download_list[nowDownload-1].readyInstall();
download_list[nowDownload-1].free=true;
if(nowDownload<allDownload){ // 如果有排队则下载下一个
...
}
}
void downloadlist::readyInstall()
{
...
ui->pushButton_install->setEnabled(true);
ui->pushButton_install->show();
ui->pushButton_2->hide();
Widget::sendNotification(tr("Finished downloading %1, awaiting to install").arg(ui->label->text()), 5000,
"/tmp/spark-store/icon_"+QString::number(num).toUtf8()+".png");
}
void downloadlist::on_pushButton_install_clicked()
{
//弹出菜单
menu_install->exec(cursor().pos());
}
downloadlist menu_install
downloadlist::install()
gdebi, dpkg, deepin-deb-installer
void downloadlist::install(int t)
{
QtConcurrent::run([=](){
QProcess installer;
installer.start("pkexec gdebi -n /tmp/spark-store/"+ui->label_filename->text().toUtf8());
installer.start("pkexec ssinstall /tmp/spark-store/"+ui->label_filename->text().toUtf8());
installer.start("deepin-deb-installer /tmp/spark-store/"+ui->label_filename->text().toUtf8());
});
}
```
**应用卸载**
```cpp
void Widget::on_pushButton_uninstall_clicked()
{
QtConcurrent::run([=](){
uninstall.start("pkexec apt purge -y "+pkgName);
});
}
```
**仓库源更新**
```cpp
// 更新源列表
void Widget::on_pushButton_updateServer_clicked()
{
QtConcurrent::run([=](){
...
QFile::remove(QDir::homePath().toUtf8()+"/.config/spark-store/server.list");
system("curl -o "+QDir::homePath().toUtf8()+"/.config/spark-store/server.list http://dcstore.shenmo.tech/store/server.list");
server.open(QDir::homePath().toUtf8()+"/.config/spark-store/server.list",std::ios::in);
...
while (getline(server,lineTmp)) {
ui->comboBox_server->addItem(QString::fromStdString(lineTmp));
}
});
}
// 更新星火商店apt源
void Widget::on_pushButton_updateApt_clicked()
{
QtConcurrent::run([=](){
comboBox_server /tmp/spark-store/sparkstore.list
bash脚本 sparkstore.list /etc/apt/sources.list.d/
使QProcess pkexec update.sh
}):
}
```
## 发送系统通知
```cpp
#include <libnotify/notify.h>
static NotifyNotification *_notify = nullptr; // 初始化
notify_init(tr("Spark\\ Store").toLocal8Bit()); // 构造函数初始化
notify_uninit(); // 析构函数调用
void Widget::sendNotification(const QString &message, const int msTimeout, const QString &icon)
{
if(_notify == nullptr)
{
_notify = notify_notification_new(tr("Spark\\ Store").toLocal8Bit(), message.toLocal8Bit(), icon.toLocal8Bit());
notify_notification_set_timeout(_notify, msTimeout);
}
else
notify_notification_update(_notify, tr("Spark\\ Store").toLocal8Bit(), message.toLocal8Bit(), icon.toLocal8Bit());
notify_notification_show(_notify, nullptr);
}
```

BIN
assets/fonts/hksnzt.ttf Normal file

Binary file not shown.

69
assets/icons.qrc Normal file
View File

@@ -0,0 +1,69 @@
<RCC>
<qresource prefix="/icons">
<file>icons/category_chat_dark.svg</file>
<file>icons/category_chat.svg</file>
<file>icons/category_develop_dark.svg</file>
<file>icons/category_develop.svg</file>
<file>icons/category_game_dark.svg</file>
<file>icons/category_game.svg</file>
<file>icons/category_graphic_dark.svg</file>
<file>icons/category_graphic.svg</file>
<file>icons/category_music_dark.svg</file>
<file>icons/category_music.svg</file>
<file>icons/category_network_dark.svg</file>
<file>icons/category_network.svg</file>
<file>icons/category_office_dark.svg</file>
<file>icons/category_office.svg</file>
<file>icons/category_others_dark.svg</file>
<file>icons/category_others.svg</file>
<file>icons/category_reading_dark.svg</file>
<file>icons/category_reading.svg</file>
<file>icons/category_system_dark.svg</file>
<file>icons/category_system.svg</file>
<file>icons/category_video_dark.svg</file>
<file>icons/category_video.svg</file>
<file>icons/downloads-symbolic_dark.svg</file>
<file>icons/downloads-symbolic.svg</file>
<file>icons/theme-symbolic_dark.svg</file>
<file>icons/theme-symbolic.svg</file>
<file>icons/homepage.svg</file>
<file>icons/homepage_dark.svg</file>
<file>icons/category_active_dark.svg</file>
<file>icons/category_active.svg</file>
<file>icons/refresh-page-dark.svg</file>
<file>icons/refresh-page.svg</file>
</qresource>
<qresource prefix="/">
<file>../Logo-Spark.png</file>
<file>../src/big_image.cpp</file>
<file>../src/big_image.h</file>
<file>../src/downloadlist.cpp</file>
<file>../src/downloadlist.h</file>
<file>../src/image_show.cpp</file>
<file>../src/image_show.h</file>
<file>../src/main.cpp</file>
<file>../src/progressload.cpp</file>
<file>../src/progressload.h</file>
<file>../src/widget.cpp</file>
<file>../src/widget.h</file>
<file>tags/a2d.png</file>
<file>tags/community.svg</file>
<file>tags/deepin.svg</file>
<file>tags/logo_icon.svg</file>
<file>tags/uos-authorize.svg</file>
<file>tags/a2d-small.png</file>
<file>tags/community-small.png</file>
<file>tags/deepin-small.png</file>
<file>tags/dtk-small.png</file>
<file>tags/uos-small.png</file>
<file>tags/community.png</file>
<file>tags/ubuntu-small.png</file>
<file>tags/ubuntu.png</file>
<file>tags/dwine5-small.png</file>
<file>tags/dwine5.svg</file>
<file>tags/dwine2-small.png</file>
</qresource>
<qresource prefix="/fonts">
<file>fonts/hksnzt.ttf</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="#536076" d="M10.138807,3.52000025 L10.138,12.5230002 L14.6066017,8.05523757 L15.3137085,8.76234435 L9.65685425,14.4191986 L4,8.76234435 L4.70710678,8.05523757 L9.138,12.4870002 L9.138807,3.52000025 L10.138807,3.52000025 Z" transform="rotate(90 9.657 11.518)"/>
</svg>

After

Width:  |  Height:  |  Size: 366 B

View File

@@ -0,0 +1,125 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
version="1.1"
id="svg22"
sodipodi:docname="category_active_16px_l.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata26">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>category_active_16px</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="987"
id="namedview24"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="-4"
inkscape:cy="8"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg22" />
<!-- Generator: Sketch 3.6.1 (26313) - http://www.bohemiancoding.com/sketch -->
<title
id="title2">category_active_16px</title>
<desc
id="desc4">Created with Sketch.</desc>
<defs
id="defs6" />
<g
id="Page-1"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
style="fill:#000000;fill-opacity:0.94999999">
<g
id="category_active_16px"
style="fill:#000000;fill-opacity:0.94999999">
<rect
id="Rectangle-1-Copy-44"
fill="#747568"
opacity="0"
x="0"
y="0"
width="16"
height="16"
style="fill:#000000;fill-opacity:0.94999999" />
<g
id="Group-2"
transform="translate(2.000000, 2.000000)"
fill="#FFFFFF"
style="fill:#000000;fill-opacity:0.94999999">
<rect
id="Rectangle-94"
x="0"
y="0"
width="2"
height="2"
style="fill:#000000;fill-opacity:0.94999999" />
<rect
id="Rectangle-97"
x="3"
y="0"
width="9"
height="2"
style="fill:#000000;fill-opacity:0.94999999" />
<rect
id="rect11"
x="0"
y="5"
width="2"
height="2"
style="fill:#000000;fill-opacity:0.94999999" />
<rect
id="rect13"
x="3"
y="5"
width="9"
height="2"
style="fill:#000000;fill-opacity:0.94999999" />
<rect
id="rect15"
x="0"
y="10"
width="2"
height="2"
style="fill:#000000;fill-opacity:0.94999999" />
<rect
id="rect17"
x="3"
y="10"
width="9"
height="2"
style="fill:#000000;fill-opacity:0.94999999" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="#536076" d="M10.138807,3.52000025 L10.138,12.5230002 L14.6066017,8.05523757 L15.3137085,8.76234435 L9.65685425,14.4191986 L4,8.76234435 L4.70710678,8.05523757 L9.138,12.4870002 L9.138807,3.52000025 L10.138807,3.52000025 Z" transform="rotate(90 9.657 11.518)"/>
</svg>

After

Width:  |  Height:  |  Size: 366 B

View File

@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
version="1.1"
id="svg22"
sodipodi:docname="category_active_16px.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata26">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="987"
id="namedview24"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg22" />
<!-- Generator: Sketch 3.6.1 (26313) - http://www.bohemiancoding.com/sketch -->
<title
id="title2">category_active_16px</title>
<desc
id="desc4">Created with Sketch.</desc>
<defs
id="defs6" />
<g
id="Page-1"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
style="fill:#ffffff;fill-opacity:0.60000002">
<g
id="category_active_16px"
style="fill:#ffffff;fill-opacity:0.60000002">
<rect
id="Rectangle-1-Copy-44"
fill="#747568"
opacity="0"
x="0"
y="0"
width="16"
height="16"
style="fill:#ffffff;fill-opacity:0.60000002" />
<g
id="Group-2"
transform="translate(2.000000, 2.000000)"
fill="#FFFFFF"
style="fill:#ffffff;fill-opacity:0.60000002">
<rect
id="Rectangle-94"
x="0"
y="0"
width="2"
height="2"
style="fill:#ffffff;fill-opacity:0.60000002" />
<rect
id="Rectangle-97"
x="3"
y="0"
width="9"
height="2"
style="fill:#ffffff;fill-opacity:0.60000002" />
<rect
id="rect11"
x="0"
y="5"
width="2"
height="2"
style="fill:#ffffff;fill-opacity:0.60000002" />
<rect
id="rect13"
x="3"
y="5"
width="9"
height="2"
style="fill:#ffffff;fill-opacity:0.60000002" />
<rect
id="rect15"
x="0"
y="10"
width="2"
height="2"
style="fill:#ffffff;fill-opacity:0.60000002" />
<rect
id="rect17"
x="3"
y="10"
width="9"
height="2"
style="fill:#ffffff;fill-opacity:0.60000002" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M0.09791679,7.31479943 C0.09791679,3.53173257 3.65198565,0.5 8,0.5 C12.3485596,0.5 15.9020832,3.53150012 15.9020832,7.31479943 C15.9020832,11.0972813 12.3485704,14.127954 8,14.127954 C7.06316558,14.127954 6.1471898,13.9862478 5.28311727,13.7134084 L2.55321759,15.327403 C2.15529088,15.5626687 1.67860204,15.1782665 1.82419813,14.7395213 L2.62951677,12.3127412 C1.03368368,11.0385392 0.09791679,9.24513974 0.09791679,7.31479943 Z M4.7455,6.9148 C4.7455,6.2248 4.1855,5.6648 3.4955,5.6648 C2.8055,5.6648 2.2455,6.2248 2.2455,6.9148 C2.2455,7.6048 2.8055,8.1648 3.4955,8.1648 C4.1855,8.1648 4.7455,7.6048 4.7455,6.9148 Z M9.2504,6.9148 C9.2504,6.2248 8.6904,5.6648 8.0004,5.6648 C7.3104,5.6648 6.7504,6.2248 6.7504,6.9148 C6.7504,7.6048 7.3104,8.1648 8.0004,8.1648 C8.6904,8.1648 9.2504,7.6048 9.2504,6.9148 Z M13.766,6.9148 C13.766,6.2248 13.206,5.6648 12.516,5.6648 C11.826,5.6648 11.266,6.2248 11.266,6.9148 C11.266,7.6048 11.826,8.1648 12.516,8.1648 C13.206,8.1648 13.766,7.6048 13.766,6.9148 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M0.09791679,7.31479943 C0.09791679,3.53173257 3.65198565,0.5 8,0.5 C12.3485596,0.5 15.9020832,3.53150012 15.9020832,7.31479943 C15.9020832,11.0972813 12.3485704,14.127954 8,14.127954 C7.06316558,14.127954 6.1471898,13.9862478 5.28311727,13.7134084 L2.55321759,15.327403 C2.15529088,15.5626687 1.67860204,15.1782665 1.82419813,14.7395213 L2.62951677,12.3127412 C1.03368368,11.0385392 0.09791679,9.24513974 0.09791679,7.31479943 Z M4.7455,6.9148 C4.7455,6.2248 4.1855,5.6648 3.4955,5.6648 C2.8055,5.6648 2.2455,6.2248 2.2455,6.9148 C2.2455,7.6048 2.8055,8.1648 3.4955,8.1648 C4.1855,8.1648 4.7455,7.6048 4.7455,6.9148 Z M9.2504,6.9148 C9.2504,6.2248 8.6904,5.6648 8.0004,5.6648 C7.3104,5.6648 6.7504,6.2248 6.7504,6.9148 C6.7504,7.6048 7.3104,8.1648 8.0004,8.1648 C8.6904,8.1648 9.2504,7.6048 9.2504,6.9148 Z M13.766,6.9148 C13.766,6.2248 13.206,5.6648 12.516,5.6648 C11.826,5.6648 11.266,6.2248 11.266,6.9148 C11.266,7.6048 11.826,8.1648 12.516,8.1648 C13.206,8.1648 13.766,7.6048 13.766,6.9148 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M3,2 L13,2 C14.1045695,2 15,2.8954305 15,4 L15,12 C15,13.1045695 14.1045695,14 13,14 L3,14 C1.8954305,14 1,13.1045695 1,12 L1,4 C1,2.8954305 1.8954305,2 3,2 Z M3.76776695,5.35355339 L6.03553391,7.62132034 L3.76776695,9.8890873 L4.47487373,10.5961941 L7.44974747,7.62132034 L4.47487373,4.64644661 L3.76776695,5.35355339 Z M5.91666667,12 L11.0833333,12 L11.0833333,11 L5.91666667,11 L5.91666667,12 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 523 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M3,2 L13,2 C14.1045695,2 15,2.8954305 15,4 L15,12 C15,13.1045695 14.1045695,14 13,14 L3,14 C1.8954305,14 1,13.1045695 1,12 L1,4 C1,2.8954305 1.8954305,2 3,2 Z M3.76776695,5.35355339 L6.03553391,7.62132034 L3.76776695,9.8890873 L4.47487373,10.5961941 L7.44974747,7.62132034 L4.47487373,4.64644661 L3.76776695,5.35355339 Z M5.91666667,12 L11.0833333,12 L11.0833333,11 L5.91666667,11 L5.91666667,12 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 553 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M11.3114315,3 C13.357501,3 15.0067163,5.17017281 15.7133188,8.05794777 C16.4086522,10.8996678 15.9150863,13.3535714 14.0872428,13.3535714 C13.3629901,13.3535714 12.7141246,13.0969142 11.9239825,12.5819693 C11.7832522,12.4902536 11.638281,12.3909224 11.461347,12.2660165 C11.3686071,12.200547 11.0517692,11.9743261 11.0062924,11.9420563 C9.76649639,11.0623107 9.01108239,10.715 8.00430016,10.715 C6.77138366,10.715 5.99921712,11.0762729 4.96661589,11.9397238 C4.93060093,11.9698391 4.48571222,12.3483964 4.35343872,12.4563717 C3.49008067,13.1611339 2.80601727,13.4628505 1.87123269,13.3869162 C0.0836355556,13.241098 -0.391076934,10.7851693 0.309935396,7.98500253 C1.02394135,5.13293317 2.67988585,3 4.7263796,3 C5.07581055,3 5.40379038,3.09122326 5.76942208,3.26509058 C5.87841375,3.31691894 5.98930228,3.37514875 6.12219409,3.44909841 C6.19628024,3.49032478 6.44963239,3.6346061 6.45727206,3.63892075 C7.10277068,4.00347855 7.50182674,4.14857143 8.01851079,4.14857143 C8.51588602,4.14857143 8.90120605,4.00650828 9.55466919,3.63859493 C9.69986269,3.55637602 9.78224829,3.50972827 9.84835639,3.47295723 C9.96412339,3.40856473 10.0609743,3.35696675 10.1556729,3.31001061 C10.567507,3.10580322 10.9247171,3 11.3114315,3 Z M5.07357978,10.107 C6.56572905,10.107 7.78410609,8.9267355 7.78410609,7.46414286 C7.78410609,6.00155021 6.56572905,4.82128571 5.07357978,4.82128571 C3.57990894,4.82128571 2.36305346,6.00089051 2.36305346,7.46414286 C2.36305346,8.9273952 3.57990894,10.107 5.07357978,10.107 Z M5.07357978,9.107 C4.12535588,9.107 3.36305346,8.36803337 3.36305346,7.46414286 C3.36305346,6.56025235 4.12535588,5.82128571 5.07357978,5.82128571 C6.02043115,5.82128571 6.78410609,6.56107184 6.78410609,7.46414286 C6.78410609,8.36721388 6.02043115,9.107 5.07357978,9.107 Z M5.03983241,8.37864286 C5.54751662,8.37864286 5.9601482,7.97792857 5.9601482,7.48935714 C5.9601482,6.99292857 5.54751662,6.59364286 5.03983241,6.59364286 C4.53067452,6.59364286 4.11804294,6.99292857 4.11804294,7.48935714 C4.11804294,7.97792857 4.53067452,8.37864286 5.03983241,8.37864286 Z M9.65408509,8.38564286 C10.1617693,8.38564286 10.5744008,7.9835 10.5744008,7.49135714 C10.5744008,6.99135714 10.1617693,6.58992857 9.65408509,6.58992857 C9.14492719,6.58992857 8.73229557,6.99135714 8.73229557,7.49135714 C8.73229557,7.9835 9.14492719,8.38564286 9.65408509,8.38564286 Z M11.3288535,9.99071429 C11.8365377,9.99071429 12.2491693,9.58928571 12.2491693,9.09214286 C12.2491693,8.59571429 11.8365377,8.19357143 11.3288535,8.19357143 C10.8196956,8.19357143 10.407064,8.59571429 10.407064,9.09214286 C10.407064,9.58928571 10.8196956,9.99071429 11.3288535,9.99071429 Z M11.3281166,6.77357143 C11.8372745,6.77357143 12.2491693,6.37142857 12.2491693,5.87357143 C12.2491693,5.37714286 11.8372745,4.97428571 11.3281166,4.97428571 C10.8174851,4.97428571 10.407064,5.37714286 10.407064,5.87357143 C10.407064,6.37142857 10.8174851,6.77357143 11.3281166,6.77357143 Z M12.9731166,8.38421429 C13.4852219,8.38421429 13.8971166,7.98135714 13.8971166,7.48921429 C13.8971166,6.98992857 13.4852219,6.5885 12.9731166,6.5885 C12.4676429,6.5885 12.0550114,6.98992857 12.0550114,7.48921429 C12.0550114,7.98135714 12.4676429,8.38421429 12.9731166,8.38421429 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M11.3114315,3 C13.357501,3 15.0067163,5.17017281 15.7133188,8.05794777 C16.4086522,10.8996678 15.9150863,13.3535714 14.0872428,13.3535714 C13.3629901,13.3535714 12.7141246,13.0969142 11.9239825,12.5819693 C11.7832522,12.4902536 11.638281,12.3909224 11.461347,12.2660165 C11.3686071,12.200547 11.0517692,11.9743261 11.0062924,11.9420563 C9.76649639,11.0623107 9.01108239,10.715 8.00430016,10.715 C6.77138366,10.715 5.99921712,11.0762729 4.96661589,11.9397238 C4.93060093,11.9698391 4.48571222,12.3483964 4.35343872,12.4563717 C3.49008067,13.1611339 2.80601727,13.4628505 1.87123269,13.3869162 C0.0836355556,13.241098 -0.391076934,10.7851693 0.309935396,7.98500253 C1.02394135,5.13293317 2.67988585,3 4.7263796,3 C5.07581055,3 5.40379038,3.09122326 5.76942208,3.26509058 C5.87841375,3.31691894 5.98930228,3.37514875 6.12219409,3.44909841 C6.19628024,3.49032478 6.44963239,3.6346061 6.45727206,3.63892075 C7.10277068,4.00347855 7.50182674,4.14857143 8.01851079,4.14857143 C8.51588602,4.14857143 8.90120605,4.00650828 9.55466919,3.63859493 C9.69986269,3.55637602 9.78224829,3.50972827 9.84835639,3.47295723 C9.96412339,3.40856473 10.0609743,3.35696675 10.1556729,3.31001061 C10.567507,3.10580322 10.9247171,3 11.3114315,3 Z M5.07357978,10.107 C6.56572905,10.107 7.78410609,8.9267355 7.78410609,7.46414286 C7.78410609,6.00155021 6.56572905,4.82128571 5.07357978,4.82128571 C3.57990894,4.82128571 2.36305346,6.00089051 2.36305346,7.46414286 C2.36305346,8.9273952 3.57990894,10.107 5.07357978,10.107 Z M5.07357978,9.107 C4.12535588,9.107 3.36305346,8.36803337 3.36305346,7.46414286 C3.36305346,6.56025235 4.12535588,5.82128571 5.07357978,5.82128571 C6.02043115,5.82128571 6.78410609,6.56107184 6.78410609,7.46414286 C6.78410609,8.36721388 6.02043115,9.107 5.07357978,9.107 Z M5.03983241,8.37864286 C5.54751662,8.37864286 5.9601482,7.97792857 5.9601482,7.48935714 C5.9601482,6.99292857 5.54751662,6.59364286 5.03983241,6.59364286 C4.53067452,6.59364286 4.11804294,6.99292857 4.11804294,7.48935714 C4.11804294,7.97792857 4.53067452,8.37864286 5.03983241,8.37864286 Z M9.65408509,8.38564286 C10.1617693,8.38564286 10.5744008,7.9835 10.5744008,7.49135714 C10.5744008,6.99135714 10.1617693,6.58992857 9.65408509,6.58992857 C9.14492719,6.58992857 8.73229557,6.99135714 8.73229557,7.49135714 C8.73229557,7.9835 9.14492719,8.38564286 9.65408509,8.38564286 Z M11.3288535,9.99071429 C11.8365377,9.99071429 12.2491693,9.58928571 12.2491693,9.09214286 C12.2491693,8.59571429 11.8365377,8.19357143 11.3288535,8.19357143 C10.8196956,8.19357143 10.407064,8.59571429 10.407064,9.09214286 C10.407064,9.58928571 10.8196956,9.99071429 11.3288535,9.99071429 Z M11.3281166,6.77357143 C11.8372745,6.77357143 12.2491693,6.37142857 12.2491693,5.87357143 C12.2491693,5.37714286 11.8372745,4.97428571 11.3281166,4.97428571 C10.8174851,4.97428571 10.407064,5.37714286 10.407064,5.87357143 C10.407064,6.37142857 10.8174851,6.77357143 11.3281166,6.77357143 Z M12.9731166,8.38421429 C13.4852219,8.38421429 13.8971166,7.98135714 13.8971166,7.48921429 C13.8971166,6.98992857 13.4852219,6.5885 12.9731166,6.5885 C12.4676429,6.5885 12.0550114,6.98992857 12.0550114,7.48921429 C12.0550114,7.98135714 12.4676429,8.38421429 12.9731166,8.38421429 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M13,2 C14.1045695,2 15,2.8954305 15,4 L15,12 C15,13.1045695 14.1045695,14 13,14 L3,14 C1.8954305,14 1,13.1045695 1,12 L1,4 C1,2.8954305 1.8954305,2 3,2 L13,2 Z M9.38816736,7.22265239 L7.95626236,10.0443009 C7.82854357,10.2959779 7.59618367,10.3016397 7.44581474,10.0701011 L6.5212474,8.6464491 C6.2918509,8.42797452 5.91137533,8.45796439 5.72281255,8.70938339 L3.09783322,12.2093834 C2.84963451,12.5403176 3.0980227,13 3.52503993,13 L12.9749655,13 C13.3830419,13 13.6350993,12.5760169 13.4251458,12.2427546 L10.2751706,7.24275461 C10.0768804,6.92800582 9.60195261,6.91724249 9.38816736,7.22265239 Z M4.5,4 C3.67157288,4 3,4.67157288 3,5.5 C3,6.32842712 3.67157288,7 4.5,7 C5.32842712,7 6,6.32842712 6,5.5 C6,4.67157288 5.32842712,4 4.5,4 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 865 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M13,2 C14.1045695,2 15,2.8954305 15,4 L15,12 C15,13.1045695 14.1045695,14 13,14 L3,14 C1.8954305,14 1,13.1045695 1,12 L1,4 C1,2.8954305 1.8954305,2 3,2 L13,2 Z M9.38816736,7.22265239 L7.95626236,10.0443009 C7.82854357,10.2959779 7.59618367,10.3016397 7.44581474,10.0701011 L6.5212474,8.6464491 C6.2918509,8.42797452 5.91137533,8.45796439 5.72281255,8.70938339 L3.09783322,12.2093834 C2.84963451,12.5403176 3.0980227,13 3.52503993,13 L12.9749655,13 C13.3830419,13 13.6350993,12.5760169 13.4251458,12.2427546 L10.2751706,7.24275461 C10.0768804,6.92800582 9.60195261,6.91724249 9.38816736,7.22265239 Z M4.5,4 C3.67157288,4 3,4.67157288 3,5.5 C3,6.32842712 3.67157288,7 4.5,7 C5.32842712,7 6,6.32842712 6,5.5 C6,4.67157288 5.32842712,4 4.5,4 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 895 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M13.9529472,2.53458892 C13.9842218,2.67532449 14,2.81906015 14,2.9632288 L14,11.5 C14,12.6045695 13.1045695,13.5 12,13.5 C10.8954305,13.5 10,12.6045695 10,11.5 C10,10.3954305 10.8954305,9.5 12,9.5 C12.364732,9.5 12.7066608,9.5976323 13.0010775,9.76818814 L13,3.81473429 C13,3.45097522 12.705115,3.15609023 12.3413559,3.15609023 C12.2949677,3.15609023 12.2487093,3.16099086 12.2033508,3.17071053 L6.52063898,4.38843451 C6.21695744,4.45350912 6,4.7218827 6,5.03245826 L6,13.5 C6,14.6045695 5.1045695,15.5 4,15.5 C2.8954305,15.5 2,14.6045695 2,13.5 C2,12.3954305 2.8954305,11.5 4,11.5 C4.364732,11.5 4.70666076,11.5976323 5.0010775,11.7681881 L5,4.08503671 C5,3.15891996 5.64322914,2.35706019 6.54729233,2.15615726 L11.5954279,1.03434935 C12.6607186,0.797618084 13.716216,1.46929822 13.9529472,2.53458892 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 929 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M13.9529472,2.53458892 C13.9842218,2.67532449 14,2.81906015 14,2.9632288 L14,11.5 C14,12.6045695 13.1045695,13.5 12,13.5 C10.8954305,13.5 10,12.6045695 10,11.5 C10,10.3954305 10.8954305,9.5 12,9.5 C12.364732,9.5 12.7066608,9.5976323 13.0010775,9.76818814 L13,3.81473429 C13,3.45097522 12.705115,3.15609023 12.3413559,3.15609023 C12.2949677,3.15609023 12.2487093,3.16099086 12.2033508,3.17071053 L6.52063898,4.38843451 C6.21695744,4.45350912 6,4.7218827 6,5.03245826 L6,13.5 C6,14.6045695 5.1045695,15.5 4,15.5 C2.8954305,15.5 2,14.6045695 2,13.5 C2,12.3954305 2.8954305,11.5 4,11.5 C4.364732,11.5 4.70666076,11.5976323 5.0010775,11.7681881 L5,4.08503671 C5,3.15891996 5.64322914,2.35706019 6.54729233,2.15615726 L11.5954279,1.03434935 C12.6607186,0.797618084 13.716216,1.46929822 13.9529472,2.53458892 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 959 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M7.99960993,0.9998 C11.8598496,0.9998 15,4.13995046 15,7.99940993 C15,11.8596496 11.8598496,14.9998 7.99960993,14.9998 C4.14015046,14.9998 1,11.8596496 1,7.99940993 C1,4.13995046 4.14015046,0.9998 7.99960993,0.9998 Z M8.86971986,11.9145 C8.56971986,12.747 8.22071986,13.122 7.99971986,13.122 C7.78521986,13.122 7.44971986,12.768 7.15571986,11.9845 C6.86571986,12.132 6.61521986,12.2485 6.36971986,12.354 C6.75321986,13.3495 7.29871986,14 7.99971986,14 C8.71921986,14 9.27521986,13.314 9.66021986,12.274 C9.41771986,12.1735 9.16171986,12.0585 8.86971986,11.9145 Z M12.0962199,3.61 C10.8027199,3.61 9.05121986,4.5085 7.94421986,5.19 C6.85371986,4.547 5.16021986,3.717 3.90321986,3.717 C3.19571986,3.717 2.85321986,4 2.69121986,4.238 C2.46021986,4.576 2.34571986,5.1655 2.90071986,6.1455 C2.82221986,6.286 2.77771986,6.448 2.77771986,6.6205 C2.77771986,7.154 3.20271986,7.5865 3.72621986,7.5865 C4.24971986,7.5865 4.67471986,7.154 4.67471986,6.6205 C4.67471986,6.087 4.25021986,5.6545 3.72621986,5.6545 L3.72621986,5.6545 L3.62121986,5.6605 C3.32971986,5.131 3.33321986,4.8355 3.39871986,4.7395 C3.46021986,4.6485 3.64921986,4.595 3.90321986,4.595 C4.30121986,4.595 4.82071986,4.7155 5.41071986,4.9325 C5.98671986,5.145 6.57721986,5.43 7.11871986,5.728 C5.99421986,6.502 5.13171986,7.25 4.36621986,8.027 C4.02471986,8.379 3.68871986,8.7615 3.39771986,9.1515 C2.30221986,10.6215 2.40671986,11.433 2.68771986,11.8555 C3.25671986,12.71 4.68721986,12.3665 5.64571986,12.014 C7.99371986,11.151 11.0597199,8.9165 12.6017199,6.848 C13.6972199,5.3785 13.5927199,4.567 13.3117199,4.1445 C13.1492199,3.9005 12.8067199,3.61 12.0962199,3.61 Z M12.2647199,8.445 C11.7407199,8.445 11.3162199,8.8775 11.3162199,9.411 C11.3162199,9.9445 11.7407199,10.377 12.2647199,10.377 L12.3937199,10.368 C12.6702199,10.88 12.6657199,11.167 12.6012199,11.2615 C12.5392199,11.352 12.3507199,11.4055 12.0967199,11.4055 C11.2957199,11.4055 10.1802199,10.933 9.46171986,10.5765 C9.22171986,10.7475 8.92321986,10.9505 8.63221986,11.136 C9.59521986,11.6545 11.0112199,12.2835 12.0967199,12.2835 C12.8042199,12.2835 13.1467199,12.0005 13.3087199,11.7625 C13.5392199,11.4255 13.6537199,10.8375 13.1032199,9.8625 C13.1737199,9.7275 13.2132199,9.574 13.2132199,9.411 C13.2132199,8.8775 12.7887199,8.445 12.2647199,8.445 Z M12.0962199,4.4875 C12.3517199,4.4875 12.5347199,4.542 12.5977199,4.6365 C12.6907199,4.776 12.6677199,5.3075 11.9147199,6.317 C10.9462199,7.6165 9.40121986,8.8925 8.04671986,9.7805 C6.94321986,10.504 5.07821986,11.5125 3.90321986,11.5125 C3.64771986,11.5125 3.46471986,11.458 3.40171986,11.3635 C3.21521986,11.083 3.61221986,10.04 5.02121986,8.601 C5.54371986,9.0665 6.10721986,9.5115 6.67921986,9.917 L6.67921986,9.917 C6.98671986,9.7555 7.25071986,9.597 7.51171986,9.4315 C6.82921986,8.9695 6.18871986,8.4705 5.65121986,7.995 C6.36621986,7.3465 7.16221986,6.738 7.95271986,6.2195 C8.64121986,6.6515 9.30521986,7.133 9.90271986,7.625 C10.1212199,7.429 10.3347199,7.226 10.5382199,7.0195 C9.99971986,6.5705 9.40971986,6.1295 8.77721986,5.711 C9.63321986,5.217 11.1197199,4.4875 12.0962199,4.4875 Z M7.99971986,2 C7.28021986,2 6.72421986,2.686 6.33921986,3.726 C6.58321986,3.827 6.83971986,3.9425 7.12971986,4.0855 C7.42971986,3.253 7.77871986,2.878 7.99971986,2.878 C8.21471986,2.878 8.54971986,3.232 8.84371986,4.0155 C9.13071986,3.8695 9.38371986,3.7515 9.62971986,3.646 C9.24671986,2.6505 8.70071986,2 7.99971986,2 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M7.99960993,0.9998 C11.8598496,0.9998 15,4.13995046 15,7.99940993 C15,11.8596496 11.8598496,14.9998 7.99960993,14.9998 C4.14015046,14.9998 1,11.8596496 1,7.99940993 C1,4.13995046 4.14015046,0.9998 7.99960993,0.9998 Z M8.86971986,11.9145 C8.56971986,12.747 8.22071986,13.122 7.99971986,13.122 C7.78521986,13.122 7.44971986,12.768 7.15571986,11.9845 C6.86571986,12.132 6.61521986,12.2485 6.36971986,12.354 C6.75321986,13.3495 7.29871986,14 7.99971986,14 C8.71921986,14 9.27521986,13.314 9.66021986,12.274 C9.41771986,12.1735 9.16171986,12.0585 8.86971986,11.9145 Z M12.0962199,3.61 C10.8027199,3.61 9.05121986,4.5085 7.94421986,5.19 C6.85371986,4.547 5.16021986,3.717 3.90321986,3.717 C3.19571986,3.717 2.85321986,4 2.69121986,4.238 C2.46021986,4.576 2.34571986,5.1655 2.90071986,6.1455 C2.82221986,6.286 2.77771986,6.448 2.77771986,6.6205 C2.77771986,7.154 3.20271986,7.5865 3.72621986,7.5865 C4.24971986,7.5865 4.67471986,7.154 4.67471986,6.6205 C4.67471986,6.087 4.25021986,5.6545 3.72621986,5.6545 L3.72621986,5.6545 L3.62121986,5.6605 C3.32971986,5.131 3.33321986,4.8355 3.39871986,4.7395 C3.46021986,4.6485 3.64921986,4.595 3.90321986,4.595 C4.30121986,4.595 4.82071986,4.7155 5.41071986,4.9325 C5.98671986,5.145 6.57721986,5.43 7.11871986,5.728 C5.99421986,6.502 5.13171986,7.25 4.36621986,8.027 C4.02471986,8.379 3.68871986,8.7615 3.39771986,9.1515 C2.30221986,10.6215 2.40671986,11.433 2.68771986,11.8555 C3.25671986,12.71 4.68721986,12.3665 5.64571986,12.014 C7.99371986,11.151 11.0597199,8.9165 12.6017199,6.848 C13.6972199,5.3785 13.5927199,4.567 13.3117199,4.1445 C13.1492199,3.9005 12.8067199,3.61 12.0962199,3.61 Z M12.2647199,8.445 C11.7407199,8.445 11.3162199,8.8775 11.3162199,9.411 C11.3162199,9.9445 11.7407199,10.377 12.2647199,10.377 L12.3937199,10.368 C12.6702199,10.88 12.6657199,11.167 12.6012199,11.2615 C12.5392199,11.352 12.3507199,11.4055 12.0967199,11.4055 C11.2957199,11.4055 10.1802199,10.933 9.46171986,10.5765 C9.22171986,10.7475 8.92321986,10.9505 8.63221986,11.136 C9.59521986,11.6545 11.0112199,12.2835 12.0967199,12.2835 C12.8042199,12.2835 13.1467199,12.0005 13.3087199,11.7625 C13.5392199,11.4255 13.6537199,10.8375 13.1032199,9.8625 C13.1737199,9.7275 13.2132199,9.574 13.2132199,9.411 C13.2132199,8.8775 12.7887199,8.445 12.2647199,8.445 Z M12.0962199,4.4875 C12.3517199,4.4875 12.5347199,4.542 12.5977199,4.6365 C12.6907199,4.776 12.6677199,5.3075 11.9147199,6.317 C10.9462199,7.6165 9.40121986,8.8925 8.04671986,9.7805 C6.94321986,10.504 5.07821986,11.5125 3.90321986,11.5125 C3.64771986,11.5125 3.46471986,11.458 3.40171986,11.3635 C3.21521986,11.083 3.61221986,10.04 5.02121986,8.601 C5.54371986,9.0665 6.10721986,9.5115 6.67921986,9.917 L6.67921986,9.917 C6.98671986,9.7555 7.25071986,9.597 7.51171986,9.4315 C6.82921986,8.9695 6.18871986,8.4705 5.65121986,7.995 C6.36621986,7.3465 7.16221986,6.738 7.95271986,6.2195 C8.64121986,6.6515 9.30521986,7.133 9.90271986,7.625 C10.1212199,7.429 10.3347199,7.226 10.5382199,7.0195 C9.99971986,6.5705 9.40971986,6.1295 8.77721986,5.711 C9.63321986,5.217 11.1197199,4.4875 12.0962199,4.4875 Z M7.99971986,2 C7.28021986,2 6.72421986,2.686 6.33921986,3.726 C6.58321986,3.827 6.83971986,3.9425 7.12971986,4.0855 C7.42971986,3.253 7.77871986,2.878 7.99971986,2.878 C8.21471986,2.878 8.54971986,3.232 8.84371986,4.0155 C9.13071986,3.8695 9.38371986,3.7515 9.62971986,3.646 C9.24671986,2.6505 8.70071986,2 7.99971986,2 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M14.6796875,1 C15.1667188,1 15.5,1.316 15.5,1.66666667 L15.5,2.33333333 C15.5,2.684 15.1667188,3 14.6796875,3 L14,3 L14,9.0952381 C14,10.147209 13.1045695,11 12,11 L10.223,11 L12.2674534,13.0443466 C12.4627155,13.2396088 12.4627155,13.5561912 12.2674534,13.7514534 C12.0721912,13.9467155 11.7556088,13.9467155 11.5603466,13.7514534 L8.9995,11.1905 L9,14.5 C9,14.7761424 8.77614237,15 8.5,15 C8.24358208,15 8.03224642,14.8069799 8.00336387,14.5583106 L8,14.5 L7.9995,11.191 L5.43965339,13.7514534 C5.25941141,13.9316954 4.97579588,13.9455601 4.77965028,13.7930477 L4.73254661,13.7514534 C4.55230463,13.5712114 4.53843986,13.2875959 4.69095231,13.0914503 L4.73254661,13.0443466 L6.776,11 L4,11 C2.8954305,11 2,10.147209 2,9.0952381 L2,3 L1.3203125,3 C0.83328125,3 0.5,2.684 0.5,2.33333333 L0.5,1.66666667 C0.5,1.316 0.83328125,1 1.3203125,1 L14.6796875,1 Z M13,3 L3,3 L3,9.05882353 C3,9.57862094 3.44771525,10 4,10 L12,10 C12.5522847,10 13,9.57862094 13,9.05882353 L13,3 Z M8,4.5 L8,6.5 L10,6.5 C10,7.6045695 9.1045695,8.5 8,8.5 C6.8954305,8.5 6,7.6045695 6,6.5 C6,5.3954305 6.8954305,4.5 8,4.5 Z M9,3.5 C10.1045695,3.5 11,4.3954305 11,5.5 L9,5.5 L9,3.5 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M14.6796875,1 C15.1667188,1 15.5,1.316 15.5,1.66666667 L15.5,2.33333333 C15.5,2.684 15.1667188,3 14.6796875,3 L14,3 L14,9.0952381 C14,10.147209 13.1045695,11 12,11 L10.223,11 L12.2674534,13.0443466 C12.4627155,13.2396088 12.4627155,13.5561912 12.2674534,13.7514534 C12.0721912,13.9467155 11.7556088,13.9467155 11.5603466,13.7514534 L8.9995,11.1905 L9,14.5 C9,14.7761424 8.77614237,15 8.5,15 C8.24358208,15 8.03224642,14.8069799 8.00336387,14.5583106 L8,14.5 L7.9995,11.191 L5.43965339,13.7514534 C5.25941141,13.9316954 4.97579588,13.9455601 4.77965028,13.7930477 L4.73254661,13.7514534 C4.55230463,13.5712114 4.53843986,13.2875959 4.69095231,13.0914503 L4.73254661,13.0443466 L6.776,11 L4,11 C2.8954305,11 2,10.147209 2,9.0952381 L2,3 L1.3203125,3 C0.83328125,3 0.5,2.684 0.5,2.33333333 L0.5,1.66666667 C0.5,1.316 0.83328125,1 1.3203125,1 L14.6796875,1 Z M13,3 L3,3 L3,9.05882353 C3,9.57862094 3.44771525,10 4,10 L12,10 C12.5522847,10 13,9.57862094 13,9.05882353 L13,3 Z M8,4.5 L8,6.5 L10,6.5 C10,7.6045695 9.1045695,8.5 8,8.5 C6.8954305,8.5 6,7.6045695 6,6.5 C6,5.3954305 6.8954305,4.5 8,4.5 Z M9,3.5 C10.1045695,3.5 11,4.3954305 11,5.5 L9,5.5 L9,3.5 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8.00031808,0.99950155 C11.8603458,0.99950155 14.9999738,4.1390565 14.9999738,7.99950155 C14.9999738,11.8599466 11.8603458,14.9995015 8.00031808,14.9995015 C4.13971544,14.9995015 0.999973754,11.8600603 0.999973754,7.99950155 C0.999973754,4.13894278 4.13971544,0.99950155 8.00031808,0.99950155 Z M11.4999738,8.99950155 C12.0526404,8.99950155 12.4999738,8.55150155 12.4999738,7.99950155 C12.4999738,7.44683488 12.0526404,6.99950155 11.4999738,6.99950155 C10.9473071,6.99950155 10.4999738,7.44683488 10.4999738,7.99950155 C10.4999738,8.55150155 10.9473071,8.99950155 11.4999738,8.99950155 Z M7.99997375,8.99950155 C8.55264042,8.99950155 8.99997375,8.55150155 8.99997375,7.99950155 C8.99997375,7.44683488 8.55264042,6.99950155 7.99997375,6.99950155 C7.44797375,6.99950155 6.99997375,7.44683488 6.99997375,7.99950155 C6.99997375,8.55150155 7.44797375,8.99950155 7.99997375,8.99950155 Z M4.49997375,8.99950155 C5.05264042,8.99950155 5.49997375,8.55150155 5.49997375,7.99950155 C5.49997375,7.44683488 5.05264042,6.99950155 4.49997375,6.99950155 C3.94797375,6.99950155 3.49997375,7.44683488 3.49997375,7.99950155 C3.49997375,8.55150155 3.94797375,8.99950155 4.49997375,8.99950155 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M8.00031808,0.99950155 C11.8603458,0.99950155 14.9999738,4.1390565 14.9999738,7.99950155 C14.9999738,11.8599466 11.8603458,14.9995015 8.00031808,14.9995015 C4.13971544,14.9995015 0.999973754,11.8600603 0.999973754,7.99950155 C0.999973754,4.13894278 4.13971544,0.99950155 8.00031808,0.99950155 Z M11.4999738,8.99950155 C12.0526404,8.99950155 12.4999738,8.55150155 12.4999738,7.99950155 C12.4999738,7.44683488 12.0526404,6.99950155 11.4999738,6.99950155 C10.9473071,6.99950155 10.4999738,7.44683488 10.4999738,7.99950155 C10.4999738,8.55150155 10.9473071,8.99950155 11.4999738,8.99950155 Z M7.99997375,8.99950155 C8.55264042,8.99950155 8.99997375,8.55150155 8.99997375,7.99950155 C8.99997375,7.44683488 8.55264042,6.99950155 7.99997375,6.99950155 C7.44797375,6.99950155 6.99997375,7.44683488 6.99997375,7.99950155 C6.99997375,8.55150155 7.44797375,8.99950155 7.99997375,8.99950155 Z M4.49997375,8.99950155 C5.05264042,8.99950155 5.49997375,8.55150155 5.49997375,7.99950155 C5.49997375,7.44683488 5.05264042,6.99950155 4.49997375,6.99950155 C3.94797375,6.99950155 3.49997375,7.44683488 3.49997375,7.99950155 C3.49997375,8.55150155 3.94797375,8.99950155 4.49997375,8.99950155 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-rule="evenodd">
<path fill="#000" d="M1.85789238,2.64258737 C4.86313703,2.21112969 6.5771729,2.75883866 7,4.28571429 L7,13.7857143 C6.27058294,12.8374721 4.43450345,12.3388115 1.49176152,12.2897326 C1.2188519,12.2852804 1,12.062748 1,11.7898021 L1,3.63241367 C1.00002467,3.13504017 1.36556687,2.71326968 1.85789238,2.64258737 Z"/>
<path fill="#000" d="M9.85789238,2.64258737 C12.863137,2.21112969 14.5771729,2.75883866 15,4.28571429 L15,13.7857143 C14.2705829,12.8374721 12.4345034,12.3388115 9.49176152,12.2897326 C9.2188519,12.2852804 9,12.062748 9,11.7898021 L9,3.63241367 C9.00002467,3.13504017 9.36556687,2.71326968 9.85789238,2.64258737 Z" transform="matrix(-1 0 0 1 24 0)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 810 B

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<g fill="none" fill-opacity=".6" fill-rule="evenodd">
<path fill="#FFF" d="M1.85789238,2.64258737 C4.86313703,2.21112969 6.5771729,2.75883866 7,4.28571429 L7,13.7857143 C6.27058294,12.8374721 4.43450345,12.3388115 1.49176152,12.2897326 C1.2188519,12.2852804 1,12.062748 1,11.7898021 L1,3.63241367 C1.00002467,3.13504017 1.36556687,2.71326968 1.85789238,2.64258737 Z"/>
<path fill="#FFF" d="M9.85789238,2.64258737 C12.863137,2.21112969 14.5771729,2.75883866 15,4.28571429 L15,13.7857143 C14.2705829,12.8374721 12.4345034,12.3388115 9.49176152,12.2897326 C9.2188519,12.2852804 9,12.062748 9,11.7898021 L9,3.63241367 C9.00002467,3.13504017 9.36556687,2.71326968 9.85789238,2.64258737 Z" transform="matrix(-1 0 0 1 24 0)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 828 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M3,14 C1.8954305,14 1,13.1045695 1,12 L1,4 C1,2.8954305 1.8954305,2 3,2 L13,2 C14.1045695,2 15,2.8954305 15,4 L15,12 C15,13.0543618 14.1841222,13.9181651 13.1492623,13.9945143 L13,14 L13,14 L3,14 Z M14,5 L2,5 L2,12 C2,12.5522847 2.44771525,13 3,13 L8.01233301,13.0001639 C8.01943442,12.9772458 8.02824971,12.9546419 8.0388094,12.9325301 L8.30383017,12.3775926 C8.34459502,12.2912196 8.34695846,12.1917404 8.30983658,12.1028011 C8.27399122,12.0159757 8.20318605,11.9486684 8.11444707,11.9170901 L7.53244707,11.7100901 C7.33313205,11.6391997 7.19999981,11.4505463 7.19999981,11.2389998 L7.19999981,10.1609998 C7.19999981,9.9491733 7.33347927,9.7603339 7.53316619,9.6896543 L8.11249002,9.4846101 C8.20258302,9.4521442 8.27390085,9.3842428 8.31058669,9.2953916 C8.34695846,9.2082592 8.34459502,9.10878 8.3048094,9.0244696 L8.0388094,8.46746956 C7.94749917,8.2762673 7.98662009,8.04827275 8.13644642,7.89844642 L8.89844642,7.13644642 C9.04827275,6.98662009 9.2762673,6.94749917 9.46746956,7.0388094 L10.022407,7.30383017 C10.10878,7.34459502 10.2082592,7.34695846 10.2971985,7.30983658 C10.3842159,7.27391194 10.4518724,7.202745 10.4837447,7.11391109 L10.6897447,6.53291109 C10.7604992,6.33335606 10.9492726,6.19999981 11.1609998,6.19999981 L12.2389998,6.19999981 C12.450727,6.19999981 12.6395004,6.33335606 12.7102549,6.53291109 L12.9156316,7.11216331 C12.9481272,7.202745 13.0157837,7.27391194 13.104608,7.31058669 C13.1917404,7.34695846 13.2912196,7.34459502 13.3755301,7.3048094 L13.9325301,7.0388094 L14,7.013 L14,5 Z M11.6999998,9.1999998 C10.8729998,9.1999998 10.1999998,9.8729998 10.1999998,10.6999998 C10.1999998,11.5269998 10.8729998,12.1999998 11.6999998,12.1999998 C12.5269998,12.1999998 13.1999998,11.5269998 13.1999998,10.6999998 C13.1999998,9.8729998 12.5269998,9.1999998 11.6999998,9.1999998 Z M13,3 L12,3 L12,4 L13,4 L13,3 Z M9,3 L8,3 L8,4 L9,4 L9,3 Z M11,3 L10,3 L10,4 L11,4 L11,3 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M3,14 C1.8954305,14 1,13.1045695 1,12 L1,4 C1,2.8954305 1.8954305,2 3,2 L13,2 C14.1045695,2 15,2.8954305 15,4 L15,12 C15,13.0543618 14.1841222,13.9181651 13.1492623,13.9945143 L13,14 L13,14 L3,14 Z M14,5 L2,5 L2,12 C2,12.5522847 2.44771525,13 3,13 L8.01233301,13.0001639 C8.01943442,12.9772458 8.02824971,12.9546419 8.0388094,12.9325301 L8.30383017,12.3775926 C8.34459502,12.2912196 8.34695846,12.1917404 8.30983658,12.1028011 C8.27399122,12.0159757 8.20318605,11.9486684 8.11444707,11.9170901 L7.53244707,11.7100901 C7.33313205,11.6391997 7.19999981,11.4505463 7.19999981,11.2389998 L7.19999981,10.1609998 C7.19999981,9.9491733 7.33347927,9.7603339 7.53316619,9.6896543 L8.11249002,9.4846101 C8.20258302,9.4521442 8.27390085,9.3842428 8.31058669,9.2953916 C8.34695846,9.2082592 8.34459502,9.10878 8.3048094,9.0244696 L8.0388094,8.46746956 C7.94749917,8.2762673 7.98662009,8.04827275 8.13644642,7.89844642 L8.89844642,7.13644642 C9.04827275,6.98662009 9.2762673,6.94749917 9.46746956,7.0388094 L10.022407,7.30383017 C10.10878,7.34459502 10.2082592,7.34695846 10.2971985,7.30983658 C10.3842159,7.27391194 10.4518724,7.202745 10.4837447,7.11391109 L10.6897447,6.53291109 C10.7604992,6.33335606 10.9492726,6.19999981 11.1609998,6.19999981 L12.2389998,6.19999981 C12.450727,6.19999981 12.6395004,6.33335606 12.7102549,6.53291109 L12.9156316,7.11216331 C12.9481272,7.202745 13.0157837,7.27391194 13.104608,7.31058669 C13.1917404,7.34695846 13.2912196,7.34459502 13.3755301,7.3048094 L13.9325301,7.0388094 L14,7.013 L14,5 Z M11.6999998,9.1999998 C10.8729998,9.1999998 10.1999998,9.8729998 10.1999998,10.6999998 C10.1999998,11.5269998 10.8729998,12.1999998 11.6999998,12.1999998 C12.5269998,12.1999998 13.1999998,11.5269998 13.1999998,10.6999998 C13.1999998,9.8729998 12.5269998,9.1999998 11.6999998,9.1999998 Z M13,3 L12,3 L12,4 L13,4 L13,3 Z M9,3 L8,3 L8,4 L9,4 L9,3 Z M11,3 L10,3 L10,4 L11,4 L11,3 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M12,2 C13.1045695,2 14,2.8954305 14,4 L14,13 C14,14.1045695 13.1045695,15 12,15 L4,15 C2.8954305,15 2,14.1045695 2,13 L2,4 C2,2.8954305 2.8954305,2 4,2 L12,2 Z M4.5,12 L3.5,12 C3.22385763,12 3,12.2238576 3,12.5 L3,12.5 L3,13 C3,13.5522847 3.44771525,14 4,14 L4,14 L4.5,14 C4.77614237,14 5,13.7761424 5,13.5 L5,13.5 L5,12.5 C5,12.2238576 4.77614237,12 4.5,12 L4.5,12 Z M12.5,12 L11.5,12 C11.2238576,12 11,12.2238576 11,12.5 L11,12.5 L11,13.5 C11,13.7761424 11.2238576,14 11.5,14 L11.5,14 L12,14 C12.5522847,14 13,13.5522847 13,13 L13,13 L13,12.5 C13,12.2238576 12.7761424,12 12.5,12 L12.5,12 Z M4.5,9 L3.5,9 C3.22385763,9 3,9.22385763 3,9.5 L3,9.5 L3,10.5 C3,10.7761424 3.22385763,11 3.5,11 L3.5,11 L4.5,11 C4.77614237,11 5,10.7761424 5,10.5 L5,10.5 L5,9.5 C5,9.22385763 4.77614237,9 4.5,9 L4.5,9 Z M12.5,9 L11.5,9 C11.2238576,9 11,9.22385763 11,9.5 L11,9.5 L11,10.5 C11,10.7761424 11.2238576,11 11.5,11 L11.5,11 L12.5,11 C12.7761424,11 13,10.7761424 13,10.5 L13,10.5 L13,9.5 C13,9.22385763 12.7761424,9 12.5,9 L12.5,9 Z M4.5,6 L3.5,6 C3.22385763,6 3,6.22385763 3,6.5 L3,6.5 L3,7.5 C3,7.77614237 3.22385763,8 3.5,8 L3.5,8 L4.5,8 C4.77614237,8 5,7.77614237 5,7.5 L5,7.5 L5,6.5 C5,6.22385763 4.77614237,6 4.5,6 L4.5,6 Z M12.5,6 L11.5,6 C11.2238576,6 11,6.22385763 11,6.5 L11,6.5 L11,7.5 C11,7.77614237 11.2238576,8 11.5,8 L11.5,8 L12.5,8 C12.7761424,8 13,7.77614237 13,7.5 L13,7.5 L13,6.5 C13,6.22385763 12.7761424,6 12.5,6 L12.5,6 Z M4.5,3 L4,3 C3.44771525,3 3,3.44771525 3,4 L3,4 L3,4.5 C3,4.77614237 3.22385763,5 3.5,5 L3.5,5 L4.5,5 C4.77614237,5 5,4.77614237 5,4.5 L5,4.5 L5,3.5 C5,3.22385763 4.77614237,3 4.5,3 L4.5,3 Z M12,3 L11.5,3 C11.2238576,3 11,3.22385763 11,3.5 L11,3.5 L11,4.5 C11,4.77614237 11.2238576,5 11.5,5 L11.5,5 L12.5,5 C12.7761424,5 13,4.77614237 13,4.5 L13,4.5 L13,4 C13,3.44771525 12.5522847,3 12,3 L12,3 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill="#FFF" fill-opacity=".6" fill-rule="evenodd" d="M12,2 C13.1045695,2 14,2.8954305 14,4 L14,13 C14,14.1045695 13.1045695,15 12,15 L4,15 C2.8954305,15 2,14.1045695 2,13 L2,4 C2,2.8954305 2.8954305,2 4,2 L12,2 Z M4.5,12 L3.5,12 C3.22385763,12 3,12.2238576 3,12.5 L3,12.5 L3,13 C3,13.5522847 3.44771525,14 4,14 L4,14 L4.5,14 C4.77614237,14 5,13.7761424 5,13.5 L5,13.5 L5,12.5 C5,12.2238576 4.77614237,12 4.5,12 L4.5,12 Z M12.5,12 L11.5,12 C11.2238576,12 11,12.2238576 11,12.5 L11,12.5 L11,13.5 C11,13.7761424 11.2238576,14 11.5,14 L11.5,14 L12,14 C12.5522847,14 13,13.5522847 13,13 L13,13 L13,12.5 C13,12.2238576 12.7761424,12 12.5,12 L12.5,12 Z M4.5,9 L3.5,9 C3.22385763,9 3,9.22385763 3,9.5 L3,9.5 L3,10.5 C3,10.7761424 3.22385763,11 3.5,11 L3.5,11 L4.5,11 C4.77614237,11 5,10.7761424 5,10.5 L5,10.5 L5,9.5 C5,9.22385763 4.77614237,9 4.5,9 L4.5,9 Z M12.5,9 L11.5,9 C11.2238576,9 11,9.22385763 11,9.5 L11,9.5 L11,10.5 C11,10.7761424 11.2238576,11 11.5,11 L11.5,11 L12.5,11 C12.7761424,11 13,10.7761424 13,10.5 L13,10.5 L13,9.5 C13,9.22385763 12.7761424,9 12.5,9 L12.5,9 Z M4.5,6 L3.5,6 C3.22385763,6 3,6.22385763 3,6.5 L3,6.5 L3,7.5 C3,7.77614237 3.22385763,8 3.5,8 L3.5,8 L4.5,8 C4.77614237,8 5,7.77614237 5,7.5 L5,7.5 L5,6.5 C5,6.22385763 4.77614237,6 4.5,6 L4.5,6 Z M12.5,6 L11.5,6 C11.2238576,6 11,6.22385763 11,6.5 L11,6.5 L11,7.5 C11,7.77614237 11.2238576,8 11.5,8 L11.5,8 L12.5,8 C12.7761424,8 13,7.77614237 13,7.5 L13,7.5 L13,6.5 C13,6.22385763 12.7761424,6 12.5,6 L12.5,6 Z M4.5,3 L4,3 C3.44771525,3 3,3.44771525 3,4 L3,4 L3,4.5 C3,4.77614237 3.22385763,5 3.5,5 L3.5,5 L4.5,5 C4.77614237,5 5,4.77614237 5,4.5 L5,4.5 L5,3.5 C5,3.22385763 4.77614237,3 4.5,3 L4.5,3 Z M12,3 L11.5,3 C11.2238576,3 11,3.22385763 11,3.5 L11,3.5 L11,4.5 C11,4.77614237 11.2238576,5 11.5,5 L11.5,5 L12.5,5 C12.7761424,5 13,4.77614237 13,4.5 L13,4.5 L13,4 C13,3.44771525 12.5522847,3 12,3 L12,3 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8,1 C11.8659932,1 15,4.13400675 15,8 C15,11.8659932 11.8659932,15 8,15 C4.13400675,15 1,11.8659932 1,8 C1,4.13400675 4.13400675,1 8,1 Z M9.5,8 L6.5,8 C6.22385763,8 6,8.22385763 6,8.5 C6,8.77614237 5.77614237,9 5.5,9 L5.5,9 L5,9 C4.89014373,9 4.78478689,9.04364023 4.70710678,9.12132034 C4.54534632,9.2830808 4.54534632,9.54534632 4.70710678,9.70710678 L4.70710678,9.70710678 L7.64644661,12.6464466 C7.84170876,12.8417088 8.15829124,12.8417088 8.35355339,12.6464466 L8.35355339,12.6464466 L11.2928932,9.70710678 C11.3705733,9.62942667 11.4142136,9.52406983 11.4142136,9.41421356 C11.4142136,9.18544973 11.2287638,9 11,9 L11,9 L10.5,9 C10.2238576,9 10,8.77614237 10,8.5 C10,8.22385763 9.77614237,8 9.5,8 L9.5,8 Z M9.5,6 L6.5,6 C6.22385763,6 6,6.22385763 6,6.5 C6,6.77614237 6.22385763,7 6.5,7 L6.5,7 L9.5,7 C9.77614237,7 10,6.77614237 10,6.5 C10,6.22385763 9.77614237,6 9.5,6 L9.5,6 Z M9.5,4 L6.5,4 C6.22385763,4 6,4.22385763 6,4.5 C6,4.77614237 6.22385763,5 6.5,5 L6.5,5 L9.5,5 C9.77614237,5 10,4.77614237 10,4.5 C10,4.22385763 9.77614237,4 9.5,4 L9.5,4 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg4"
sodipodi:docname="downloads-symbolic_dark.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="982"
id="namedview6"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
fill="#FFF"
fill-opacity=".8"
fill-rule="evenodd"
d="M8,1 C11.8659932,1 15,4.13400675 15,8 C15,11.8659932 11.8659932,15 8,15 C4.13400675,15 1,11.8659932 1,8 C1,4.13400675 4.13400675,1 8,1 Z M9.5,8 L6.5,8 C6.22385763,8 6,8.22385763 6,8.5 C6,8.77614237 5.77614237,9 5.5,9 L5.5,9 L5,9 C4.89014373,9 4.78478689,9.04364023 4.70710678,9.12132034 C4.54534632,9.2830808 4.54534632,9.54534632 4.70710678,9.70710678 L4.70710678,9.70710678 L7.64644661,12.6464466 C7.84170876,12.8417088 8.15829124,12.8417088 8.35355339,12.6464466 L8.35355339,12.6464466 L11.2928932,9.70710678 C11.3705733,9.62942667 11.4142136,9.52406983 11.4142136,9.41421356 C11.4142136,9.18544973 11.2287638,9 11,9 L11,9 L10.5,9 C10.2238576,9 10,8.77614237 10,8.5 C10,8.22385763 9.77614237,8 9.5,8 L9.5,8 Z M9.5,6 L6.5,6 C6.22385763,6 6,6.22385763 6,6.5 C6,6.77614237 6.22385763,7 6.5,7 L6.5,7 L9.5,7 C9.77614237,7 10,6.77614237 10,6.5 C10,6.22385763 9.77614237,6 9.5,6 L9.5,6 Z M9.5,4 L6.5,4 C6.22385763,4 6,4.22385763 6,4.5 C6,4.77614237 6.22385763,5 6.5,5 L6.5,5 L9.5,5 C9.77614237,5 10,4.77614237 10,4.5 C10,4.22385763 9.77614237,4 9.5,4 L9.5,4 Z"
id="path2"
style="fill:#ffffff;fill-opacity:0.60000002" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

68
assets/icons/homepage.svg Normal file
View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
version="1.1"
id="svg8"
sodipodi:docname="homepage.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="982"
id="namedview10"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<!-- Generator: Sketch 56.3 (81716) - https://sketch.com -->
<title
id="title2">category_recommend</title>
<desc
id="desc4">Created with Sketch.</desc>
<g
id="category_recommend"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
style="fill:#000000;fill-opacity:0.86666667">
<path
d="M8,12.6085145 L4.54924088,14.5160472 C4.06572729,14.783327 3.74708518,14.5504931 3.83503048,14.0113448 L4.5,9.93475242 L1.69148737,7.05624503 C1.30958944,6.6648293 1.44637232,6.27932454 1.97881505,6.19797453 L5.83688104,5.60851449 L7.5726373,1.91049416 C7.8086632,1.40764212 8.19196238,1.40897492 8.4273627,1.91049416 L10.163119,5.60851449 L14.0211849,6.19797453 C14.5617696,6.28056851 14.6893983,6.66586674 14.3085126,7.05624503 L11.5,9.93475242 L12.1649695,14.0113448 C12.2540356,14.557364 11.9269904,14.7793014 11.4507591,14.5160472 L8,12.6085145 Z"
id="Star"
fill="#536076"
style="fill:#000000;fill-opacity:0.86666667" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
viewBox="0 0 16 16"
version="1.1"
id="svg8"
sodipodi:docname="homepage_dark.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="982"
id="namedview10"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="-15.932203"
inkscape:cy="2.5762712"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<!-- Generator: Sketch 56.3 (81716) - https://sketch.com -->
<title
id="title2">category_recommend</title>
<desc
id="desc4">Created with Sketch.</desc>
<g
id="category_recommend"
stroke="none"
stroke-width="1"
fill="none"
fill-rule="evenodd"
style="fill:#ffffff;fill-opacity:0.60000002">
<path
d="M8,12.6085145 L4.54924088,14.5160472 C4.06572729,14.783327 3.74708518,14.5504931 3.83503048,14.0113448 L4.5,9.93475242 L1.69148737,7.05624503 C1.30958944,6.6648293 1.44637232,6.27932454 1.97881505,6.19797453 L5.83688104,5.60851449 L7.5726373,1.91049416 C7.8086632,1.40764212 8.19196238,1.40897492 8.4273627,1.91049416 L10.163119,5.60851449 L14.0211849,6.19797453 C14.5617696,6.28056851 14.6893983,6.66586674 14.3085126,7.05624503 L11.5,9.93475242 L12.1649695,14.0113448 C12.2540356,14.557364 11.9269904,14.7793014 11.4507591,14.5160472 L8,12.6085145 Z"
id="Star"
fill="#C5CFE0"
style="fill:#ffffff;fill-opacity:0.60000002" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
height="16"
width="16"
sodipodi:docname="refresh-page-dark.svg"
xml:space="preserve"
viewBox="0 0 16 16"
y="0px"
x="0px"
id="Layer_1"
version="1.1"><metadata
id="metadata9"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7" /><sodipodi:namedview
inkscape:current-layer="Layer_1"
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:cy="8.8351119"
inkscape:cx="12.452215"
inkscape:zoom="34.711876"
showgrid="true"
id="namedview5"
inkscape:window-height="958"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff"><inkscape:grid
id="grid834"
type="xygrid" /></sodipodi:namedview>
<g
style="fill:#ffffff;fill-opacity:0.60000002"
transform="scale(0.03125,0.0312082)"
id="XMLID_2_">
<path
style="fill:#ffffff;fill-opacity:0.60000002"
d="M 436.6,75.4 C 390.1,28.9 326.7,0 256,0 114.5,0 0,114.5 0,256 0,397.5 114.5,512 256,512 375.2,512 474.8,430.1 503.6,320.2 h -67 C 410.5,394.7 339.8,447.7 256,447.7 149.9,447.7 64.2,362.1 64.2,255.9 64.2,149.7 149.9,64.2 256,64.2 c 53.1,0 100.5,22.3 135,56.8 L 287.7,224.3 H 512 V 0 Z"
id="XMLID_4_" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
height="16"
width="16"
sodipodi:docname="refresh-page.svg"
xml:space="preserve"
viewBox="0 0 16 16"
y="0px"
x="0px"
id="Layer_1"
version="1.1"><metadata
id="metadata9"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs7" /><sodipodi:namedview
inkscape:current-layer="Layer_1"
inkscape:window-maximized="1"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:cy="8.8351119"
inkscape:cx="12.452215"
inkscape:zoom="34.711876"
showgrid="true"
id="namedview5"
inkscape:window-height="958"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff"><inkscape:grid
id="grid834"
type="xygrid" /></sodipodi:namedview>
<g
transform="scale(0.03125,0.0312082)"
id="XMLID_2_">
<path
d="M 436.6,75.4 C 390.1,28.9 326.7,0 256,0 114.5,0 0,114.5 0,256 0,397.5 114.5,512 256,512 375.2,512 474.8,430.1 503.6,320.2 h -67 C 410.5,394.7 339.8,447.7 256,447.7 149.9,447.7 64.2,362.1 64.2,255.9 64.2,149.7 149.9,64.2 256,64.2 c 53.1,0 100.5,22.3 135,56.8 L 287.7,224.3 H 512 V 0 Z"
id="XMLID_4_" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M3.5,14 C3.22385763,14 3,13.7761424 3,13.5 C3,13.2238576 3.22385763,13 3.5,13 L7,13 L7,12 L2,12 C1.44771525,12 1,11.5522847 1,11 L15,11 C15,11.5522847 14.5522847,12 14,12 L9,12 L9,13 L12.5,13 C12.7761424,13 13,13.2238576 13,13.5 C13,13.7761424 12.7761424,14 12.5,14 L3.5,14 Z M13,2 C14.1045695,2 15,2.8954305 15,4 L15,10 L1,10 L1,4 C1,2.8954305 1.8954305,2 3,2 L13,2 Z"/>
</svg>

After

Width:  |  Height:  |  Size: 494 B

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg4"
sodipodi:docname="theme-symbolic_dark.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="982"
id="namedview6"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
fill="#FFF"
fill-opacity=".8"
fill-rule="evenodd"
d="M3.5,14 C3.22385763,14 3,13.7761424 3,13.5 C3,13.2238576 3.22385763,13 3.5,13 L7,13 L7,12 L2,12 C1.44771525,12 1,11.5522847 1,11 L15,11 C15,11.5522847 14.5522847,12 14,12 L9,12 L9,13 L12.5,13 C12.7761424,13 13,13.2238576 13,13.5 C13,13.7761424 12.7761424,14 12.5,14 L3.5,14 Z M13,2 C14.1045695,2 15,2.8954305 15,4 L15,10 L1,10 L1,4 C1,2.8954305 1.8954305,2 3,2 L13,2 Z"
id="path2"
style="opacity:1;fill:#ffffff;fill-opacity:0.60000002" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
assets/tags/a2d-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/tags/a2d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
assets/tags/community.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

240
assets/tags/community.svg Normal file
View File

@@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
sodipodi:docname="deepin-community-store.svg"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
id="svg8"
version="1.1"
viewBox="0 0 200 200"
height="200mm"
width="200mm">
<defs
id="defs2">
<linearGradient
id="linearGradient1200"
inkscape:collect="always">
<stop
id="stop1196"
offset="0"
style="stop-color:#000000;stop-opacity:0.1299435" />
<stop
id="stop1198"
offset="1"
style="stop-color:#dadada;stop-opacity:0.81960785" />
</linearGradient>
<linearGradient
inkscape:collect="always"
id="linearGradient1138">
<stop
style="stop-color:#99e7ea;stop-opacity:1"
offset="0"
id="stop1134" />
<stop
style="stop-color:#007ffc;stop-opacity:1"
offset="1"
id="stop1136" />
</linearGradient>
<linearGradient
id="linearGradient1128"
inkscape:collect="always">
<stop
id="stop1124"
offset="0"
style="stop-color:#99e7ea;stop-opacity:1" />
<stop
id="stop1126"
offset="1"
style="stop-color:#007ffc;stop-opacity:1" />
</linearGradient>
<inkscape:path-effect
only_selected="false"
apply_with_weight="true"
apply_no_weight="true"
helper_size="0"
steps="2"
weight="33.333333"
is_visible="true"
id="path-effect960"
effect="bspline" />
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.98112945,0,3.7714702)"
r="90.135414"
fy="199.86011"
fx="100.35268"
cy="199.86011"
cx="100.35268"
id="radialGradient1130"
xlink:href="#linearGradient1128"
inkscape:collect="always" />
<radialGradient
r="90.135414"
fy="199.86011"
fx="100.35268"
cy="199.86011"
cx="100.35268"
gradientTransform="matrix(1,0,0,0.98112945,0,3.7714702)"
gradientUnits="userSpaceOnUse"
id="radialGradient1132"
xlink:href="#linearGradient1138"
inkscape:collect="always" />
<radialGradient
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,0.98112945,0,3.7714702)"
r="90.135414"
fy="199.86011"
fx="100.35268"
cy="199.86011"
cx="100.35268"
id="radialGradient1202"
xlink:href="#linearGradient1200"
inkscape:collect="always" />
<filter
id="filter1448"
inkscape:label="Drop Shadow"
style="color-interpolation-filters:sRGB;">
<feFlood
id="feFlood1438"
result="flood"
flood-color="rgb(145,145,145)"
flood-opacity="0.372549" />
<feComposite
id="feComposite1440"
result="composite1"
operator="in"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur1442"
result="blur"
stdDeviation="5.2918"
in="composite1" />
<feOffset
id="feOffset1444"
result="offset"
dy="0"
dx="0" />
<feComposite
id="feComposite1446"
result="composite2"
operator="over"
in2="offset"
in="SourceGraphic" />
</filter>
<filter
id="filter2201"
inkscape:label="Drop Shadow"
style="color-interpolation-filters:sRGB;">
<feFlood
id="feFlood2191"
result="flood"
flood-color="rgb(145,145,145)"
flood-opacity="0.372549" />
<feComposite
id="feComposite2193"
result="composite1"
operator="in"
in2="SourceGraphic"
in="flood" />
<feGaussianBlur
id="feGaussianBlur2195"
result="blur"
stdDeviation="3.76995"
in="composite1" />
<feOffset
id="feOffset2197"
result="offset"
dy="0"
dx="0" />
<feComposite
id="feComposite2199"
result="composite2"
operator="over"
in2="offset"
in="SourceGraphic" />
</filter>
</defs>
<sodipodi:namedview
inkscape:document-rotation="0"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="-8"
inkscape:window-height="705"
inkscape:window-width="1366"
showgrid="false"
inkscape:current-layer="layer2"
inkscape:document-units="mm"
inkscape:cy="507.94585"
inkscape:cx="120.33119"
inkscape:zoom="0.35"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(0,-97)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1" />
<g
inkscape:label="Layer 2"
id="layer2"
inkscape:groupmode="layer">
<path
inkscape:connector-curvature="0"
id="path1002"
d="m 91.937746,32.561862 c 0,0 11.145084,-0.157476 22.599704,6.928753 11.45465,7.086223 18.11074,13.857508 20.27783,18.266716 2.16708,4.409213 9.28755,12.125333 9.13277,26.297793 -0.15488,14.17244 -3.40543,23.620766 -8.97797,31.494326 -5.57254,7.87359 -15.63405,13.85751 -27.70786,14.17247 -12.073834,0.31494 -19.813464,-7.55863 -22.444934,-11.96786 -2.63147,-4.4092 -3.71502,-13.85751 -0.46438,-20.628766 3.25065,-6.77132 8.3588,-6.77132 10.06152,-6.14141 1.70272,0.6299 2.16709,1.5747 3.09585,3.30689 0.92875,1.73219 1.54793,1.41726 2.941094,0.47243 1.39311,-0.94484 1.85748,-2.04715 1.54792,-3.46439 -0.30958,-1.41726 -2.167114,-3.14944 -3.715054,-3.62186 -1.54791,-0.47241 -3.71502,-1.88966 -6.81087,-1.41721 -3.09585,0.47238 -9.13276,2.04711 -14.24091,8.97585 -5.10815,6.928746 -4.48899,17.636836 -1.39313,22.675926 3.09585,5.0391 8.97796,14.48739 21.98054,17.79431 13.002594,3.30693 34.054354,-6.45633 41.329594,-21.57361 7.27524,-15.117296 7.43004,-22.203516 7.12048,-34.643766 C 145.96036,67.048164 134.97008,48.466503 122.74148,41.69522 110.51288,34.923934 101.38012,30.987141 91.937746,32.561862 Z"
style="fill:#ffc344;fill-opacity:1;stroke:none;stroke-width:0.309114px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path1012"
d="m 98.407556,95.469094 c 0,0 -3.06474,-2.8951 -5.80111,2.22698 -2.73637,5.122046 -4.04983,9.687366 -1.31346,15.254856 2.73637,5.56745 8.42801,8.90792 17.184454,8.79659 8.75636,-0.11148 15.21419,-2.22699 19.0451,-8.5739 3.83094,-6.34692 6.7862,-11.02357 7.11457,-13.361906 0.32839,-2.33835 2.07965,0.334036 1.53239,2.338336 -0.54728,2.00426 -0.43783,5.9015 1.09454,5.12204 1.53237,-0.77942 2.73637,-2.00427 2.95526,-1.44753 0.21893,0.55673 -1.75127,4.00859 -2.68162,5.73449 -0.93039,1.7259 -3.83094,5.90153 -5.5275,7.51607 -1.69652,1.61458 -4.04981,3.89724 -6.84092,5.56747 -2.79109,1.67024 -7.11454,3.61887 -9.52255,4.06427 -2.40801,0.44539 -7.22403,1.39184 -9.96042,1.2805 -2.73635,-0.11137 -6.238924,-0.61243 -10.124564,-2.56104 -3.88565,-1.94859 -8.09966,-4.95505 -9.74148,-7.96148 -1.64182,-3.00643 -4.15928,-5.73449 -3.61201,-13.30623 0.54728,-7.571746 3.01001,-11.468986 4.87074,-13.250556 1.86073,-1.7816 4.5971,-2.56105 6.40311,-2.17131 1.806,0.38971 2.95528,1.44755 3.3931,2.22697 0.43781,0.77944 1.14928,2.22699 1.53237,2.50538 z"
style="fill:#f06767;fill-opacity:1;stroke:none;stroke-width:0.309114px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path1014"
d="m 126.2091,135.55481 c 0,0 13.13457,-7.6831 19.26404,-19.82016 6.12948,-12.13707 8.7564,-19.931516 7.99021,-31.845916 -0.76619,-11.91436 -2.62692,-6.01286 -0.54728,-11.13493 2.07964,-5.12208 -1.31345,-15.25486 0.10943,-15.922952 1.42292,-0.668097 4.48765,4.453972 5.3633,8.573902 0.87562,4.11992 4.70654,16.81372 1.64181,32.9594 -3.06472,16.145636 -10.28872,22.603906 -15.10475,26.946546 -4.81603,4.34261 -15.7615,11.91437 -17.40332,11.80302 -1.64183,-0.11148 -1.86073,-0.11148 -1.31348,-1.55891 z"
style="fill:#3f62eb;fill-opacity:1;stroke:none;stroke-width:0.309114px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path1016"
d="m 102.56686,112.17145 c 0,0 7.00512,1.5589 12.36838,-1.78156 5.3633,-3.3405 9.5226,-8.79661 10.17931,-10.912246 0.65672,-2.11564 0.76619,1.892936 1.53236,-0.11125 0.76618,-2.00432 3.83093,-6.01288 2.29855,-15.36624 -1.53237,-9.35333 -1.64182,-9.79875 -4.48762,-14.80947 -2.84586,-5.01072 -9.63207,-11.914367 -13.79134,-14.141356 -4.15927,-2.226986 -9.96037,-5.567464 -17.950604,-5.344766 -7.9902,0.222699 -5.36328,-0.334048 -13.02512,1.002146 -7.66184,1.336187 -14.55749,5.010717 -16.85604,7.015006 -2.29855,2.004286 -8.42802,7.46041 -10.61712,10.46684 -2.1891,3.00643 -8.20911,9.79874 -11.3833,19.26344 -3.17419,9.46469 -4.48765,10.46683 -4.70656,16.702396 -0.21891,6.23557 0.54727,7.90578 -0.76618,8.46256 -1.31346,0.55673 -1.09455,-4.67668 -0.9851,-8.35123 0.10946,-3.6745 0.10946,-13.250556 4.92547,-23.940086 4.81601,-10.68954 13.35349,-19.59749 18.1695,-22.826621 4.81601,-3.229128 10.39821,-7.571752 19.04514,-9.687392 8.64693,-2.115635 17.29386,-1.781586 22.65716,-0.779443 5.363304,1.002145 13.681874,4.453974 18.169504,7.905802 4.48766,3.45183 9.41314,7.683104 13.13459,14.586764 3.72146,6.90365 4.70654,15.70025 4.59709,19.37477 -0.10943,3.67455 -1.97019,12.137106 -4.81601,16.257016 -2.84583,4.11993 -6.67674,9.0193 -10.61711,10.80089 -3.94039,1.78157 -8.75642,2.33833 -12.69675,0.55674 -3.94039,-1.78161 -3.72147,-2.44969 -4.3782,-4.34263 z"
style="fill:#fce102;fill-opacity:1;stroke:none;stroke-width:0.309114px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path1018"
d="m 102.56686,112.17145 c 0,0 5.54674,1.56707 10.22918,-0.55878 4.68248,-2.12587 6.4239,-4.17301 7.54615,-5.3934 1.12223,-1.22042 3.25064,-3.50376 3.83112,-4.56669 0.58046,-1.06292 1.19962,-1.692816 1.19962,-2.086486 0,-0.39369 -1.08353,-1.33853 -0.0386,-3.62186 1.04482,-2.28333 1.97361,-7.51928 1.50922,-9.88134 -0.46438,-2.36207 -1.54792,-15.47161 -10.83547,-24.2113 -9.28753,-8.739679 -18.497714,-9.763243 -18.497714,-9.763243 0,0 14.705314,4.645415 21.593574,18.739133 6.88828,14.09374 4.64376,23.14835 0.23218,28.65986 -4.41158,5.511506 -10.68068,6.141406 -12.38342,4.724146 -1.70268,-1.41725 -5.2113,6.47164 -4.38574,7.95996 z"
style="fill:#5ed938;fill-opacity:1;stroke:none;stroke-width:0.309114px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path1020"
d="m 84.662496,61.615394 c 0,0 -9.90672,-0.0787 -17.41416,4.88161 -7.50743,4.96037 -11.14506,8.9759 -13.23476,12.12533 -2.08969,3.14945 -4.48898,7.47991 -4.17939,7.40118 0.30958,-0.0788 9.05536,-12.2828 15.86623,-15.43223 6.81087,-3.14944 13.62174,-7.55865 22.98669,-4.33049 9.36495,3.22819 13.776544,7.71612 15.788844,6.61383 2.0123,-1.1023 2.3993,-2.44082 1.23835,-3.9368 -1.16094,-1.49598 -9.364964,-8.81842 -21.051804,-7.32243 z"
style="fill:#8fdbe9;fill-opacity:1;stroke:none;stroke-width:0.309114px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path1022"
d="m 69.839846,124.53124 c 0.65673,0.33404 5.58219,8.90795 9.52257,10.35548 3.94037,1.44755 6.56728,1.55888 7.0051,2.227 0.43782,0.66809 0.32837,4.00858 3.83092,5.45614 3.50256,1.44753 19.920794,6.01284 24.627334,6.45824 4.70658,0.4454 0.76621,3.22911 3.61202,4.23125 2.84584,1.00217 14.99532,1.5589 17.95061,0.33405 2.95527,-1.22483 2.95527,1.1135 -2.1891,3.1178 -5.14437,2.00427 -18.71677,6.79231 -27.58261,5.67882 -8.865864,-1.1135 -19.373534,-3.00644 -25.284094,-7.23772 -5.91056,-4.23126 -8.42802,-6.1242 -6.23892,-6.45824 2.18909,-0.33407 7.9902,5.9015 10.50766,6.56959 2.51746,0.66809 4.5971,0.66809 3.06473,-0.8908 -1.53236,-1.55888 -11.49275,-8.46253 -12.47784,-8.1285 -0.9851,0.33405 -3.06474,0.55674 -4.81602,-1.78159 -1.75127,-2.33832 -10.94548,-15.25485 -10.39821,-22.1585 0.54728,-6.90365 2.29856,-5.12208 4.3782,-2.56103 2.07964,2.56103 4.48765,4.78801 4.48765,4.78801 z"
style="fill:#fd7aff;fill-opacity:1;stroke:none;stroke-width:0.309114px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

35
assets/tags/deepin.svg Normal file
View File

@@ -0,0 +1,35 @@
<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<path d="m17,129c0,-61.30371 49.69629,-111 111,-111c61.30371,0 111,49.69629 111,111c0,61.30371 -49.69629,111 -111,111c-61.30371,0 -111,-49.69629 -111,-111z" id="deepin-launcher-b"/>
<filter filterUnits="objectBoundingBox" y="-6.3%" x="-8.1%" height="116.2%" width="116.2%" id="deepin-launcher-a">
<feGaussianBlur stdDeviation="5"/>
</filter>
<path d="m172.29023,47.20405c-13.1683,-7.14564 -28.25541,-11.20405 -44.29023,-11.20405c-3.85759,0 -7.66034,0.23489 -11.39471,0.69114c-13.8375,19.06416 -21.01047,50.16415 -20.43985,69.1948c0,0 -0.90954,28.19993 18.37748,38.20231c0,0 17.33291,7.61701 29.14502,-17.01295c0,0 8.11834,-13.89983 4.81381,-45.31395c0,0 3.16155,0.55793 3.51901,1.05927c0.35746,0.49728 6.98241,24.18523 2.32747,44.13339c0,0 -4.28556,23.44132 -25.35592,28.80234c-21.06242,5.36102 -37.47784,-7.60893 -48.62269,-19.82688c-8.29983,-9.09853 -20.62176,-33.53254 -26.69028,-62.84231c-11.72709,15.56323 -18.67934,34.92741 -18.67934,55.91495c0,14.49236 3.31502,28.21045 9.22816,40.43737c20.53097,6.06549 72.70224,17.88328 105.89216,-6.44123c21.96964,-16.10443 19.13893,-41.89451 19.13893,-41.89451c-0.36372,-19.61754 -12.30727,-39.10374 -12.30727,-39.10374c46.44186,42.01354 18.99265,88.68931 18.99265,88.68931c-12.77926,26.10154 -39.04908,42.79526 -62.02961,50.25104c4.59324,0.69782 9.29685,1.05965 14.08498,1.05965c51.36266,0 93,-41.63639 93,-92.99789c0,-21.72407 -7.44877,-41.70884 -19.93152,-57.53933c-4.54487,0.31322 -9.825,0.49664 -15.30337,0.31684c0,0 -24.70889,1.15387 -38.56418,8.0646c0,0 -10.33212,4.60716 -20.65999,12.41858c0,0 -2.19192,1.09575 -2.08593,5.12183c0.09327,4.01362 -2.10288,14.71385 -9.42058,20.98539c0,0 -5.22329,2.68544 -2.61165,6.52889c0,0 3.52742,5.12183 8.49633,-0.25734c0,0 12.81233,-13.18228 13.59668,-34.42501c0,0 4.05314,-3.4616 10.45506,-4.48264c0,0 1.17863,31.86824 -14.63539,47.86878c0,0 -15.04241,16.38239 -19.87565,-7.93593c0,0 -5.88469,-23.16861 24.45027,-50.68289c0,0 20.448,-20.42091 32.46751,-29.98388c1.66104,0.69233 3.29908,1.42749 4.91265,2.20406l-0.00001,-0.00001zm-44.29023,183.79595c-56.33322,0 -102,-45.66583 -102,-101.99789c0,-56.33281 45.66752,-102.00211 102,-102.00211c56.33248,0 102,45.6693 102,102.00211c0,56.33206 -45.66678,101.99789 -102,101.99789z" id="deepin-launcher-f"/>
<filter filterUnits="objectBoundingBox" y="-.5%" x="-.5%" height="102%" width="101%" id="deepin-launcher-e"/>
<filter filterUnits="objectBoundingBox" y="-.5%" x="-.5%" height="102%" width="101%" id="deepin-launcher-g"/>
<linearGradient y2="97.178%" y1="4.64%" x2="50%" x1="50%" id="deepin-launcher-c">
<stop stop-color="#00ABFF" offset="0%"/>
<stop stop-color="#0163FA" offset="100%"/>
</linearGradient>
<linearGradient y2="100%" y1="0%" x2="50%" x1="50%" id="deepin-launcher-d">
<stop stop-color="#32BBFF" offset="0%"/>
<stop stop-color="#004FC5" offset="100%"/>
</linearGradient>
</defs>
<g>
<title>background</title>
<rect fill="none" id="canvas_background" height="514" width="514" y="-1" x="-1"/>
</g>
<g>
<title>Layer 1</title>
<g stroke="null" id="svg_1" fill-rule="evenodd" fill="none">
<use x="0" y="0" transform="matrix(2.15315318107605,0,0,2.15315318107605,-19.603604078292847,-20.756757259368896) " stroke="null" id="svg_2" xlink:href="#deepin-launcher-b" filter="url(#deepin-launcher-a)" fill="#000"/>
<use x="0" y="0" transform="matrix(2.15315318107605,0,0,2.15315318107605,-19.603604078292847,-20.756757259368896) " stroke="url(#deepin-launcher-d)" id="svg_3" xlink:href="#deepin-launcher-b" stroke-width="2" fill="url(#deepin-launcher-c)"/>
<g stroke="null" id="svg_4" fill-rule="nonzero">
<use x="0" y="0" transform="matrix(2.15315318107605,0,0,2.15315318107605,-19.603604078292847,-20.756757259368896) " stroke="null" id="svg_5" xlink:href="#deepin-launcher-f" filter="url(#deepin-launcher-e)" fill="#000"/>
<use x="0" y="0" transform="matrix(2.15315318107605,0,0,2.15315318107605,-19.603604078292847,-20.756757259368896) " stroke="null" id="svg_6" xlink:href="#deepin-launcher-f" fill="#F0F9FF"/>
<use x="0" y="0" transform="matrix(2.15315318107605,0,0,2.15315318107605,-19.603604078292847,-20.756757259368896) " stroke="null" id="svg_7" xlink:href="#deepin-launcher-f" filter="url(#deepin-launcher-g)" fill="#000"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
assets/tags/dtk-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

1
assets/tags/dwine5.svg Normal file
View File

@@ -0,0 +1 @@
<svg width="305" height="304" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" overflow="hidden"><defs><clipPath id="clip0"><path d="M688 378 993 378 993 682 688 682Z" fill-rule="evenodd" clip-rule="evenodd"/></clipPath><clipPath id="clip1"><path d="M751.382 385.273 984.326 440.078 929.522 673.022 696.578 618.218Z" fill-rule="evenodd" clip-rule="evenodd"/></clipPath><clipPath id="clip2"><path d="M751.382 385.273 984.326 440.078 929.522 673.022 696.578 618.218Z" fill-rule="evenodd" clip-rule="evenodd"/></clipPath><clipPath id="clip3"><path d="M751.382 385.273 984.326 440.078 929.522 673.022 696.578 618.218Z" fill-rule="evenodd" clip-rule="evenodd"/></clipPath></defs><g clip-path="url(#clip0)" transform="translate(-688 -378)"><path d="M689 529.5C689 445.829 756.829 378 840.5 378 924.171 378 992 445.829 992 529.5 992 613.171 924.171 681 840.5 681 756.829 681 689 613.171 689 529.5Z" fill="#A20000" fill-rule="evenodd"/><g clip-path="url(#clip1)"><g clip-path="url(#clip2)"><g clip-path="url(#clip3)"><path d="M812.478 604.512 826.339 545.597C790.456 531.483 772.809 490.952 786.924 455.069 792.525 440.83 802.648 428.825 815.737 420.901L910.837 443.275C931.459 475.856 921.763 518.985 889.182 539.607 876.253 547.79 860.994 551.499 845.751 550.164L831.89 609.079 851.302 613.646C856.662 614.908 859.986 620.276 858.724 625.636 857.463 630.996 852.095 634.32 846.735 633.058L788.499 619.357C783.138 618.096 779.815 612.728 781.076 607.368 782.338 602.007 787.705 598.684 793.066 599.945L812.478 604.512ZM803.34 469.2 900.4 492.035C901.355 477.612 900.407 467.146 897.544 460.634L819.896 442.366C814.431 446.918 808.915 455.864 803.34 469.2Z" fill="#FFFFFF"/></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

23
assets/tags/logo_icon.svg Normal file
View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>logo icon</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#00F1FF" offset="0%"></stop>
<stop stop-color="#008AFF" offset="100%"></stop>
</linearGradient>
</defs>
<g id="light" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1" transform="translate(-460.000000, -159.000000)">
<g id="tittlebar" transform="translate(450.000000, 150.000000)">
<g id="logo-icon" transform="translate(10.000000, 9.000000)">
<g>
<rect id="矩形" fill="url(#linearGradient-1)" x="0" y="0" width="32" height="32" rx="8"></rect>
<path d="M23,25 L23,24.0002278 C21.6666667,24.0002278 21,24.0002278 21,24.0002278 L21,20 L22,20 L22,19 L21,19 L21,17 L20,17.5 L20,19 L19,19 L19,20 L20,20 L20,24.0002278 C20,24.0002278 20,24.0002278 20,24.0002278 C20,24.5523868 20.4476132,25 20.9997722,25 C20.9998481,25 20.9999241,25 21,25 L23,25 Z M24.0210414,23.9789586 L24.0210414,22.2215556 L24.0210414,22.2215556 L24.6565969,21.6226667 L27.2207674,25 L29.0052118,25 L25.6099302,20.7304444 L28.4678057,18.0074755 L26.6711391,18.0074755 L24.0210414,20.6204444 L24,15.5 L23,15 L23,25 C23.5639056,25 24.0210414,24.5428642 24.0210414,23.9789586 Z" id="tk" fill="#FFFFFF" fill-rule="nonzero"></path>
<path d="M10.275,24 C13.175,24 15.35,23.2 16.85,21.6 C18.275,20.075 19,17.825 19,15 C19,12.15 18.275,10.05 16.85,8.55 C15.35,6.95 13.175,6 10.275,6 L4,6 L4,24 L10.275,24 Z M9.725,21 L7,21 L7,9 L9.725,9 C11.95,9 13.575,9.15 14.6,10.175 C15.6,11.175 16,12.75 16,15 C16,17.2 15.6,18.9 14.6,19.95 C13.575,20.975 11.95,21 9.725,21 Z" id="D" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
assets/tags/ubuntu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<defs>
<linearGradient id="uos-托盘1-a" x1="15.968%" x2="100%" y1="14.224%" y2="60.554%">
<stop offset="0%" stop-color="#0071FF"/>
<stop offset="48.72%" stop-color="#00E8FC"/>
<stop offset="100%" stop-color="#00A2FF"/>
</linearGradient>
</defs>
<g fill="none" transform="translate(1 1)">
<circle cx="9" cy="9" r="9" fill="url(#uos-托盘1-a)"/>
<path fill="#FFF" d="M13,4.5 C13.5128358,4.5 13.9355072,4.88604019 13.9932723,5.38337887 L14,5.5 L14,9.5 C14,12.5 12,14.5 9,14.5 C6,14.5 4,12.5 4.0043492,9.70016408 L4,9.5 L4,5.5 C4,4.94771525 4.44771525,4.5 5,4.5 C5.51283584,4.5 5.93550716,4.88604019 5.99327227,5.38337887 L6,5.5 L6,9.5 C6,11.5 7.5,12.5 9,12.5 C10.5,12.5 12,11.5 12,9.5 L12,5.5 C12,4.94771525 12.4477153,4.5 13,4.5 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 873 B

BIN
assets/tags/uos-small.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

13
assets/tags/uos.svg Normal file
View File

@@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
<defs>
<linearGradient id="uos-托盘1-a" x1="15.968%" x2="100%" y1="14.224%" y2="60.554%">
<stop offset="0%" stop-color="#0071FF"/>
<stop offset="48.72%" stop-color="#00E8FC"/>
<stop offset="100%" stop-color="#00A2FF"/>
</linearGradient>
</defs>
<g fill="none" transform="translate(1 1)">
<circle cx="9" cy="9" r="9" fill="url(#uos-托盘1-a)"/>
<path fill="#FFF" d="M13,4.5 C13.5128358,4.5 13.9355072,4.88604019 13.9932723,5.38337887 L14,5.5 L14,9.5 C14,12.5 12,14.5 9,14.5 C6,14.5 4,12.5 4.0043492,9.70016408 L4,9.5 L4,5.5 C4,4.94771525 4.44771525,4.5 5,4.5 C5.51283584,4.5 5.93550716,4.88604019 5.99327227,5.38337887 L6,5.5 L6,9.5 C6,11.5 7.5,12.5 9,12.5 C10.5,12.5 12,11.5 12,9.5 L12,5.5 C12,4.94771525 12.4477153,4.5 13,4.5 Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 873 B

20
build.sh Executable file
View File

@@ -0,0 +1,20 @@
#!/bin/sh
realpath=`realpath $0`
cd `dirname $realpath`
mkdir -p build && cd build
/usr/lib/qt5/bin/qmake ../spark-store-project.pro -spec linux-g++ CONFIG+=qtquickcompiler && /usr/bin/make qmake_all
make -j$(cat /proc/cpuinfo | grep "processor" | wc -l)
cd ..
cp ./ssinstall ./debian/opt/durapps/spark-store/bin/
cp ./spark-dstore-patch ./debian/opt/durapps/spark-store/bin/
cp ./build/src/spark-store ./debian/opt/durapps/spark-store/bin/
cp ./translations/*.qm ./debian/usr/share/spark-store/translations/
version=$(cat ./debian/DEBIAN/control | grep "Version" | awk -F ' ' '{print $2}')
fakeroot dpkg -b ./debian ./

View File

@@ -1,52 +0,0 @@
# - Try to find GDK 3
# Once done, this will define
#
# GDK3_FOUND - system has GDK 3
# GDK3_INCLUDE_DIRS - the GDK 3 include directories
# GDK3_LIBRARIES - link these to use GDK 3
#
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
# Copyright (C) 2013 Igalia S.L.
#
# 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 HOLDER AND ITS 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 ITS
# 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.
# Source from:
# https://sources.debian.org/src/qtwebkit-opensource-src/5.212.0%7Ealpha2-21/Source/cmake/FindGDK3.cmake/
find_package(PkgConfig)
pkg_check_modules(GDK3 gdk-3.0)
set(VERSION_OK TRUE)
if (GDK3_VERSION)
if (GDK3_FIND_VERSION_EXACT)
if (NOT("${GDK3_FIND_VERSION}" VERSION_EQUAL "${GDK3_VERSION}"))
set(VERSION_OK FALSE)
endif ()
else ()
if ("${GDK3_VERSION}" VERSION_LESS "${GDK3_FIND_VERSION}")
set(VERSION_OK FALSE)
endif ()
endif ()
endif ()
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GDK3 DEFAULT_MSG GDK3_INCLUDE_DIRS GDK3_LIBRARIES VERSION_OK)

View File

@@ -1,125 +0,0 @@
# - Try to find Glib and its components (gio, gobject etc)
# Once done, this will define
#
# GLIB_FOUND - system has Glib
# GLIB_INCLUDE_DIRS - the Glib include directories
# GLIB_LIBRARIES - link these to use Glib
#
# Optionally, the COMPONENTS keyword can be passed to find_package()
# and Glib components can be looked for. Currently, the following
# components can be used, and they define the following variables if
# found:
#
# gio: GLIB_GIO_LIBRARIES
# gobject: GLIB_GOBJECT_LIBRARIES
# gmodule: GLIB_GMODULE_LIBRARIES
# gthread: GLIB_GTHREAD_LIBRARIES
#
# Note that the respective _INCLUDE_DIR variables are not set, since
# all headers are in the same directory as GLIB_INCLUDE_DIRS.
#
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
#
# 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 HOLDER AND ITS 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 ITS
# 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.
# Source from:
# https://sources.debian.org/src/qtwebkit-opensource-src/5.212.0%7Ealpha2-21/Source/cmake/FindGLIB.cmake/
find_package(PkgConfig)
pkg_check_modules(PC_GLIB QUIET glib-2.0)
find_library(GLIB_LIBRARIES
NAMES glib-2.0
HINTS ${PC_GLIB_LIBDIR}
${PC_GLIB_LIBRARY_DIRS}
)
# Files in glib's main include path may include glibconfig.h, which,
# for some odd reason, is normally in $LIBDIR/glib-2.0/include.
get_filename_component(_GLIB_LIBRARY_DIR ${GLIB_LIBRARIES} PATH)
find_path(GLIBCONFIG_INCLUDE_DIR
NAMES glibconfig.h
HINTS ${PC_LIBDIR} ${PC_LIBRARY_DIRS} ${_GLIB_LIBRARY_DIR}
${PC_GLIB_INCLUDEDIR} ${PC_GLIB_INCLUDE_DIRS}
PATH_SUFFIXES glib-2.0/include
)
find_path(GLIB_INCLUDE_DIR
NAMES glib.h
HINTS ${PC_GLIB_INCLUDEDIR}
${PC_GLIB_INCLUDE_DIRS}
PATH_SUFFIXES glib-2.0
)
set(GLIB_INCLUDE_DIRS ${GLIB_INCLUDE_DIR} ${GLIBCONFIG_INCLUDE_DIR})
# Version detection
if (EXISTS "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h")
file(READ "${GLIBCONFIG_INCLUDE_DIR}/glibconfig.h" GLIBCONFIG_H_CONTENTS)
string(REGEX MATCH "#define GLIB_MAJOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
set(GLIB_VERSION_MAJOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "#define GLIB_MINOR_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
set(GLIB_VERSION_MINOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "#define GLIB_MICRO_VERSION ([0-9]+)" _dummy "${GLIBCONFIG_H_CONTENTS}")
set(GLIB_VERSION_MICRO "${CMAKE_MATCH_1}")
set(GLIB_VERSION "${GLIB_VERSION_MAJOR}.${GLIB_VERSION_MINOR}.${GLIB_VERSION_MICRO}")
endif ()
# Additional Glib components. We only look for libraries, as not all of them
# have corresponding headers and all headers are installed alongside the main
# glib ones.
foreach (_component ${GLIB_FIND_COMPONENTS})
if (${_component} STREQUAL "gio")
find_library(GLIB_GIO_LIBRARIES NAMES gio-2.0 HINTS ${_GLIB_LIBRARY_DIR})
set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GIO_LIBRARIES)
elseif (${_component} STREQUAL "gobject")
find_library(GLIB_GOBJECT_LIBRARIES NAMES gobject-2.0 HINTS ${_GLIB_LIBRARY_DIR})
set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GOBJECT_LIBRARIES)
elseif (${_component} STREQUAL "gmodule")
find_library(GLIB_GMODULE_LIBRARIES NAMES gmodule-2.0 HINTS ${_GLIB_LIBRARY_DIR})
set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GMODULE_LIBRARIES)
elseif (${_component} STREQUAL "gthread")
find_library(GLIB_GTHREAD_LIBRARIES NAMES gthread-2.0 HINTS ${_GLIB_LIBRARY_DIR})
set(ADDITIONAL_REQUIRED_VARS ${ADDITIONAL_REQUIRED_VARS} GLIB_GTHREAD_LIBRARIES)
elseif (${_component} STREQUAL "gio-unix")
# gio-unix is compiled as part of the gio library, but the include paths
# are separate from the shared glib ones. Since this is currently only used
# by WebKitGTK+ we don't go to extraordinary measures beyond pkg-config.
pkg_check_modules(GIO_UNIX QUIET gio-unix-2.0)
endif ()
endforeach ()
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GLIB REQUIRED_VARS GLIB_INCLUDE_DIRS GLIB_LIBRARIES ${ADDITIONAL_REQUIRED_VARS}
VERSION_VAR GLIB_VERSION)
mark_as_advanced(
GLIBCONFIG_INCLUDE_DIR
GLIB_GIO_LIBRARIES
GLIB_GIO_UNIX_LIBRARIES
GLIB_GMODULE_LIBRARIES
GLIB_GOBJECT_LIBRARIES
GLIB_GTHREAD_LIBRARIES
GLIB_INCLUDE_DIR
GLIB_INCLUDE_DIRS
GLIB_LIBRARIES
)

View File

@@ -1,58 +0,0 @@
# - Try to find LibNotify
# This module defines the following variables:
#
# LIBNOTIFY_FOUND - LibNotify was found
# LIBNOTIFY_INCLUDE_DIRS - the LibNotify include directories
# LIBNOTIFY_LIBRARIES - link these to use LibNotify
#
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
# Copyright (C) 2014 Collabora Ltd.
#
# 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 HOLDER AND ITS 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 ITS
# 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.
# Source from:
# https://sources.debian.org/src/qtwebkit-opensource-src/5.212.0~alpha2-21/Source/cmake/FindLibNotify.cmake/
find_package(PkgConfig)
pkg_check_modules(LIBNOTIFY QUIET libnotify)
find_path(LIBNOTIFY_INCLUDE_DIRS
NAMES notify.h
HINTS ${LIBNOTIFY_INCLUDEDIR}
${LIBNOTIFY_INCLUDE_DIRS}
PATH_SUFFIXES libnotify
)
find_library(LIBNOTIFY_LIBRARIES
NAMES notify
HINTS ${LIBNOTIFY_LIBDIR}
${LIBNOTIFY_LIBRARY_DIRS}
)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibNotify REQUIRED_VARS LIBNOTIFY_INCLUDE_DIRS LIBNOTIFY_LIBRARIES
VERSION_VAR LIBNOTIFY_VERSION)
mark_as_advanced(
LIBNOTIFY_INCLUDE_DIRS
LIBNOTIFY_LIBRARIES
)

View File

@@ -1,51 +0,0 @@
# - FindXCB
#
# Copyright 2015 Valve Coporation
find_package(PkgConfig)
if(NOT XCB_FIND_COMPONENTS)
set(XCB_FIND_COMPONENTS xcb)
endif()
include(FindPackageHandleStandardArgs)
set(XCB_FOUND true)
set(XCB_INCLUDE_DIRS "")
set(XCB_LIBRARIES "")
foreach(comp ${XCB_FIND_COMPONENTS})
# component name
string(TOUPPER ${comp} compname)
string(REPLACE "-" "_" compname ${compname})
# header name
string(REPLACE "xcb-" "" headername xcb/${comp}.h)
# library name
set(libname ${comp})
pkg_check_modules(PC_${comp} QUIET ${comp})
find_path(${compname}_INCLUDE_DIR NAMES ${headername}
HINTS
${PC_${comp}_INCLUDEDIR}
${PC_${comp}_INCLUDE_DIRS}
)
find_library(${compname}_LIBRARY NAMES ${libname}
HINTS
${PC_${comp}_LIBDIR}
${PC_${comp}_LIBRARY_DIRS}
)
find_package_handle_standard_args(${comp}
FOUND_VAR ${comp}_FOUND
REQUIRED_VARS ${compname}_INCLUDE_DIR ${compname}_LIBRARY)
mark_as_advanced(${compname}_INCLUDE_DIR ${compname}_LIBRARY)
list(APPEND XCB_INCLUDE_DIRS ${${compname}_INCLUDE_DIR})
list(APPEND XCB_LIBRARIES ${${compname}_LIBRARY})
if(NOT ${comp}_FOUND)
set(XCB_FOUND false)
endif()
endforeach()
list(REMOVE_DUPLICATES XCB_INCLUDE_DIRS)

View File

@@ -1,335 +0,0 @@
# git_watcher.cmake
# https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/git_watcher.cmake
#
# Released under the MIT License.
# https://raw.githubusercontent.com/andrew-hardin/cmake-git-version-tracking/master/LICENSE
# This file defines a target that monitors the state of a git repo.
# If the state changes (e.g. a commit is made), then a file gets reconfigured.
# Here are the primary variables that control script behavior:
#
# PRE_CONFIGURE_FILE (REQUIRED)
# -- The path to the file that'll be configured.
#
# POST_CONFIGURE_FILE (REQUIRED)
# -- The path to the configured PRE_CONFIGURE_FILE.
#
# GIT_STATE_FILE (OPTIONAL)
# -- The path to the file used to store the previous build's git state.
# Defaults to the current binary directory.
#
# GIT_WORKING_DIR (OPTIONAL)
# -- The directory from which git commands will be run.
# Defaults to the directory with the top level CMakeLists.txt.
#
# GIT_EXECUTABLE (OPTIONAL)
# -- The path to the git executable. It'll automatically be set if the
# user doesn't supply a path.
#
# GIT_FAIL_IF_NONZERO_EXIT (optional)
# -- Raise a FATAL_ERROR if any of the git commands return a non-zero
# exit code. This is set to TRUE by default. You can set this to FALSE
# if you'd like the build to continue even if a git command fails.
#
# DESIGN
# - This script was designed similar to a Python application
# with a Main() function. I wanted to keep it compact to
# simplify "copy + paste" usage.
#
# - This script is invoked under two CMake contexts:
# 1. Configure time (when build files are created).
# 2. Build time (called via CMake -P).
# The first invocation is what registers the script to
# be executed at build time.
#
# MODIFICATIONS
# You may wish to track other git properties like when the last
# commit was made. There are two sections you need to modify,
# and they're tagged with a ">>>" header.
# Short hand for converting paths to absolute.
macro(PATH_TO_ABSOLUTE var_name)
get_filename_component(${var_name} "${${var_name}}" ABSOLUTE)
endmacro()
# Check that a required variable is set.
macro(CHECK_REQUIRED_VARIABLE var_name)
if(NOT DEFINED ${var_name})
message(FATAL_ERROR "The \"${var_name}\" variable must be defined.")
endif()
PATH_TO_ABSOLUTE(${var_name})
endmacro()
# Check that an optional variable is set, or, set it to a default value.
macro(CHECK_OPTIONAL_VARIABLE_NOPATH var_name default_value)
if(NOT DEFINED ${var_name})
set(${var_name} ${default_value})
endif()
endmacro()
# Check that an optional variable is set, or, set it to a default value.
# Also converts that path to an abspath.
macro(CHECK_OPTIONAL_VARIABLE var_name default_value)
CHECK_OPTIONAL_VARIABLE_NOPATH(${var_name} ${default_value})
PATH_TO_ABSOLUTE(${var_name})
endmacro()
CHECK_REQUIRED_VARIABLE(PRE_CONFIGURE_FILE)
CHECK_REQUIRED_VARIABLE(POST_CONFIGURE_FILE)
CHECK_OPTIONAL_VARIABLE(GIT_STATE_FILE "${CMAKE_BINARY_DIR}/git-state-hash")
CHECK_OPTIONAL_VARIABLE(GIT_WORKING_DIR "${CMAKE_SOURCE_DIR}")
CHECK_OPTIONAL_VARIABLE_NOPATH(GIT_FAIL_IF_NONZERO_EXIT TRUE)
# Check the optional git variable.
# If it's not set, we'll try to find it using the CMake packaging system.
if(NOT DEFINED GIT_EXECUTABLE)
find_package(Git QUIET REQUIRED)
endif()
CHECK_REQUIRED_VARIABLE(GIT_EXECUTABLE)
set(_state_variable_names
GIT_RETRIEVED_STATE
GIT_HEAD_SHA1
GIT_IS_DIRTY
GIT_AUTHOR_NAME
GIT_AUTHOR_EMAIL
GIT_COMMIT_DATE_ISO8601
GIT_COMMIT_SUBJECT
GIT_COMMIT_BODY
GIT_DESCRIBE
# >>>
# 1. Add the name of the additional git variable you're interested in monitoring
# to this list.
)
# Macro: RunGitCommand
# Description: short-hand macro for calling a git function. Outputs are the
# "exit_code" and "output" variables.
macro(RunGitCommand)
execute_process(COMMAND
"${GIT_EXECUTABLE}" ${ARGV}
WORKING_DIRECTORY "${_working_dir}"
RESULT_VARIABLE exit_code
OUTPUT_VARIABLE output
ERROR_VARIABLE stderr
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT exit_code EQUAL 0)
set(ENV{GIT_RETRIEVED_STATE} "false")
# Issue 26: git info not properly set
#
# Check if we should fail if any of the exit codes are non-zero.
if(GIT_FAIL_IF_NONZERO_EXIT)
string(REPLACE ";" " " args_with_spaces "${ARGV}")
message(FATAL_ERROR "${stderr} (${GIT_EXECUTABLE} ${args_with_spaces})")
endif()
endif()
endmacro()
# Function: GetGitState
# Description: gets the current state of the git repo.
# Args:
# _working_dir (in) string; the directory from which git commands will be executed.
function(GetGitState _working_dir)
# This is an error code that'll be set to FALSE if the
# RunGitCommand ever returns a non-zero exit code.
set(ENV{GIT_RETRIEVED_STATE} "true")
# Get whether or not the working tree is dirty.
RunGitCommand(status --porcelain)
if(NOT exit_code EQUAL 0)
set(ENV{GIT_IS_DIRTY} "false")
else()
if(NOT "${output}" STREQUAL "")
set(ENV{GIT_IS_DIRTY} "true")
else()
set(ENV{GIT_IS_DIRTY} "false")
endif()
endif()
# There's a long list of attributes grabbed from git show.
set(object HEAD)
RunGitCommand(show -s "--format=%H" ${object})
if(exit_code EQUAL 0)
set(ENV{GIT_HEAD_SHA1} ${output})
endif()
RunGitCommand(show -s "--format=%an" ${object})
if(exit_code EQUAL 0)
set(ENV{GIT_AUTHOR_NAME} "${output}")
endif()
RunGitCommand(show -s "--format=%ae" ${object})
if(exit_code EQUAL 0)
set(ENV{GIT_AUTHOR_EMAIL} "${output}")
endif()
RunGitCommand(show -s "--format=%ci" ${object})
if(exit_code EQUAL 0)
set(ENV{GIT_COMMIT_DATE_ISO8601} "${output}")
endif()
RunGitCommand(show -s "--format=%s" ${object})
if(exit_code EQUAL 0)
# Escape quotes
string(REPLACE "\"" "\\\"" output "${output}")
set(ENV{GIT_COMMIT_SUBJECT} "${output}")
endif()
RunGitCommand(show -s "--format=%b" ${object})
if(exit_code EQUAL 0)
if(output)
# Escape quotes
string(REPLACE "\"" "\\\"" output "${output}")
# Escape line breaks in the commit message.
string(REPLACE "\r\n" "\\r\\n\\\r\n" safe "${output}")
if(safe STREQUAL output)
# Didn't have windows lines - try unix lines.
string(REPLACE "\n" "\\n\\\n" safe "${output}")
endif()
else()
# There was no commit body - set the safe string to empty.
set(safe "")
endif()
set(ENV{GIT_COMMIT_BODY} "\"${safe}\"")
else()
set(ENV{GIT_COMMIT_BODY} "\"\"") # empty string.
endif()
# Get output of git describe
RunGitCommand(describe --tags ${object})
if(NOT exit_code EQUAL 0)
set(ENV{GIT_DESCRIBE} "unknown")
else()
set(ENV{GIT_DESCRIBE} "${output}")
endif()
# >>>
# 2. Additional git properties can be added here via the
# "execute_process()" command. Be sure to set them in
# the environment using the same variable name you added
# to the "_state_variable_names" list.
endfunction()
# Function: GitStateChangedAction
# Description: this function is executed when the state of the git
# repository changes (e.g. a commit is made).
function(GitStateChangedAction)
foreach(var_name ${_state_variable_names})
set(${var_name} $ENV{${var_name}})
endforeach()
configure_file("${PRE_CONFIGURE_FILE}" "${POST_CONFIGURE_FILE}" @ONLY)
endfunction()
# Function: HashGitState
# Description: loop through the git state variables and compute a unique hash.
# Args:
# _state (out) string; a hash computed from the current git state.
function(HashGitState _state)
set(ans "")
foreach(var_name ${_state_variable_names})
string(SHA256 ans "${ans}$ENV{${var_name}}")
endforeach()
set(${_state} ${ans} PARENT_SCOPE)
endfunction()
# Function: CheckGit
# Description: check if the git repo has changed. If so, update the state file.
# Args:
# _working_dir (in) string; the directory from which git commands will be ran.
# _state_changed (out) bool; whether or no the state of the repo has changed.
function(CheckGit _working_dir _state_changed)
# Get the current state of the repo.
GetGitState("${_working_dir}")
# Convert that state into a hash that we can compare against
# the hash stored on-disk.
HashGitState(state)
# Issue 14: post-configure file isn't being regenerated.
#
# Update the state to include the SHA256 for the pre-configure file.
# This forces the post-configure file to be regenerated if the
# pre-configure file has changed.
file(SHA256 ${PRE_CONFIGURE_FILE} preconfig_hash)
string(SHA256 state "${preconfig_hash}${state}")
# Check if the state has changed compared to the backup on disk.
if(EXISTS "${GIT_STATE_FILE}")
file(READ "${GIT_STATE_FILE}" OLD_HEAD_CONTENTS)
if(OLD_HEAD_CONTENTS STREQUAL "${state}")
# State didn't change.
set(${_state_changed} "false" PARENT_SCOPE)
return()
endif()
endif()
# The state has changed.
# We need to update the state file on disk.
# Future builds will compare their state to this file.
file(WRITE "${GIT_STATE_FILE}" "${state}")
set(${_state_changed} "true" PARENT_SCOPE)
endfunction()
# Function: SetupGitMonitoring
# Description: this function sets up custom commands that make the build system
# check the state of git before every build. If the state has
# changed, then a file is configured.
function(SetupGitMonitoring)
add_custom_target(check_git
ALL
DEPENDS ${PRE_CONFIGURE_FILE}
BYPRODUCTS
${POST_CONFIGURE_FILE}
${GIT_STATE_FILE}
COMMENT "Checking the git repository for changes..."
COMMAND
${CMAKE_COMMAND}
-D_BUILD_TIME_CHECK_GIT=TRUE
-DGIT_WORKING_DIR=${GIT_WORKING_DIR}
-DGIT_EXECUTABLE=${GIT_EXECUTABLE}
-DGIT_STATE_FILE=${GIT_STATE_FILE}
-DPRE_CONFIGURE_FILE=${PRE_CONFIGURE_FILE}
-DPOST_CONFIGURE_FILE=${POST_CONFIGURE_FILE}
-DGIT_FAIL_IF_NONZERO_EXIT=${GIT_FAIL_IF_NONZERO_EXIT}
-P "${CMAKE_CURRENT_LIST_FILE}")
endfunction()
# Function: Main
# Description: primary entry-point to the script. Functions are selected based
# on whether it's configure or build time.
function(Main)
if(_BUILD_TIME_CHECK_GIT)
# Check if the repo has changed.
# If so, run the change action.
CheckGit("${GIT_WORKING_DIR}" changed)
if(changed OR NOT EXISTS "${POST_CONFIGURE_FILE}")
GitStateChangedAction()
endif()
else()
# >> Executes at configure time.
SetupGitMonitoring()
endif()
endfunction()
# And off we go...
Main()

12
debian/DEBIAN/control vendored Normal file
View File

@@ -0,0 +1,12 @@
Package: spark-store
Version: 3.0.3-7
Maintainer: shenmo <shenmo@spark-app.store>
Section: utils
Source: https://gitee.com/deepin-community-store/spark-store
Homepage: ttps://gitee.com/deepin-community-store/spark-store
Architecture: amd64
Priority: optional
Depends: libc6 (>= 2.14), libgcc1 (>= 1:3.0), libstdc++6 (>= 5.2), libqt5core5a (>= 5.11.0~rc1), libqt5gui5 (>= 5.11.0~rc1), libqt5widgets5 (>= 5.11.0~rc1), libqt5network5 (>= 5.11.0~rc1), libqt5webenginewidgets5 (>= 5.11.0~rc1), libqt5concurrent5 (>= 5.11.0~rc1), libdtkcore5 (>= 5.2.1-1), libdtkwidget5 (>= 5.2.1-1), libdtkgui5 (>= 5.2.0-1), libglib2.0-0, libgdk-pixbuf2.0-0, libnotify4, wget, curl, gnupg
Description: Spark Store version 3.0.3-7 update
Provides: deepin-app-store
Conflicts: spark-dstore-patch

33
debian/DEBIAN/postinst vendored Executable file
View File

@@ -0,0 +1,33 @@
#!/bin/sh
if [ "$1" = "triggered" ]; then
echo '------------星火应用商店现已集成UOS包补丁工具---------------'
if [ -f "/usr/bin/deepin-app-store-tool" ]; then
echo '----------检测到已安装深度应用商店,不运行补丁---------------'
exit 0
fi
echo '--------检测到Uniontech标准软件包运行补丁以修正安装--------'
/usr/local/bin/spark-dstore-patch
echo '-----------spark-dstore-patch补丁工具已运行完毕-----------'
else
mkdir -p /usr/local/bin
ln -s -f /opt/durapps/spark-store/bin/spark-store /usr/local/bin/spark-store
ln -s -f /opt/durapps/spark-store/bin/ssinstall /usr/local/bin/ssinstall
ln -s -f /opt/durapps/spark-store/bin/spark-dstore-patch /usr/local/bin/spark-dstore-patch
cd /tmp/spark-store-install
wget https://d.store.deepinos.org.cn/dcs-repo.gpg-key.asc
apt-key add dcs-repo.gpg-key.asc
update-icon-caches /usr/share/icons/hicolor || true
update-desktop-database /usr/share/applications || true
xdg-mime default spark-store.desktop x-scheme-handler/spk
update-mime-database /usr/share/mime || true
exit 0
fi
exit 0
# /tmp/spark-store-install/feedback.sh

9
debian/DEBIAN/postrm vendored Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
rm /usr/local/bin/spark-store
rm /usr/local/bin/ssinstall
rm /usr/local/bin/spark-dstore-patch
update-icon-caches /usr/share/icons/hicolor || true
update-desktop-database /usr/share/applications || true
update-mime-database /usr/share/mime || true

1
debian/DEBIAN/triggers vendored Normal file
View File

@@ -0,0 +1 @@
interest-noawait /opt/apps

View File

@@ -0,0 +1,3 @@
Package: *
Pin: origin *.deepinos.org.cn
Pin-Priority: 400

View File

@@ -0,0 +1 @@
deb [by-hash=force] https://d.store.deepinos.org.cn /

Binary file not shown.

BIN
debian/opt/durapps/spark-store/bin/spark-store vendored Executable file

Binary file not shown.

View File

@@ -0,0 +1,3 @@
#!/bin/sh
dpkg -i $1 || apt install -yf || dpkg -P $1

9
debian/tmp/spark-store-install/feedback.sh vendored Executable file
View File

@@ -0,0 +1,9 @@
#!/bin/sh
echo "From:sparkstorefeedback@163.com
To:sparkstorefeedback@163.com
Subject: spark-store_3.0.2: $(lsb_release -a | grep "Description" | sed -e "s#\t#@#" | cut -d "@" -f 2)
$(uname -a)" | tee /tmp/spark-store-install/feedback.txt > /dev/null
curl -s --url "smtp://smtp.163.com" --mail-from "sparkstorefeedback@163.com" --mail-rcpt "sparkstorefeedback@163.com" --upload-file /tmp/spark-store-install/feedback.txt --user "sparkstorefeedback@163.com:YWYGLQNOPLWNNJJY"

View File

@@ -0,0 +1,13 @@
[Desktop Entry]
Encoding=UTF-8
Type=Application
Categories=System;
Exec=spark-store %u
Icon=spark-store
Name=Spark Store
Name[zh_CN]=星火应用商店
Keywords=appstore;
Terminal=false
StartupNotify=true
StartupWMClass=spark-store
MimeType=x-scheme-handler/spk

Binary file not shown.

View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,52 +0,0 @@
# 项目结构和命名规范
## 文件夹结构
### cmake
主要用于 CMake 配置时需要用到的 CMake 模块脚本。
### gui
主要用于显示界面的 C++ 代码文件(即包含 Qt Widgets 代码),无论包含多少与其他组件的联系,都在这个目录内。
这包括 SpkUi 的自定义界面组件、商店主界面自身的 Page 类等等。
### inc
项目中所有以 `#include "xxx.h"` 方式包含到代码中的标头文件,全部放入此目录。
标头文件并不强求目录结构明确,文件用途或来源特殊的除外。
### src
商店主体逻辑。包含基础的 `SpkStore` 类、`main.cpp` 等核心逻辑。
新加入的逻辑如单个功能多于一个cpp文件则必须分装到一个目录内。
### plugin
适配 Deepin 以及其他平台的平台相关插件。
## 命名规范
### 通用规范
类名、成员、方法名一律采用大驼峰形式。例如,`SpkTitleBar::SetTitle` 方法。
C++ 规范要求的和第三方库有较大差异的除外。例如,`SpkUiMessage::_notify`成员。
临时变量采用小驼峰形式或全小写。
名称要对功能要有基础的描述,例如,`SpkUi::SpkCategorySelector` 类。抽象核心逻辑除外。
### 类名
如非第三方代码,一般以 `Spk` 前缀标明。
实现 UI 的类都应归于 `SpkUi` 命名空间。
## 类定义
### 一般规则
Qt 类的 `Q_OBJECT` 应置于类定义最顶端。
`public` `protected``private` 等标签中只应该包含一类成员,
如单个 `public` 标签内只能包含方法,或成员。
信号、槽等不得与普通方法混合。
<!--TODO-->

View File

@@ -1,6 +0,0 @@
# 翻译
由于CMake和Qt的稀烂集成我们不能使用CMake自动lupdate更新翻译。
如果需要更新翻译,请使用`make run_lupdate`目标进行。qm文件的编译无需其他操作只需build即可。

View File

@@ -1,314 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-only
#include "page/spkpageappdetails.h"
#include "spkutils.h"
#include "spkappitem.h"
namespace SpkUi
{
constexpr QSize SpkPageAppDetails::IconSize;
void SpkPageAppDetails::LoadAppResources(QString aPkgName, QString aIcon, QStringList aScreenshots,
QStringList aTags)
{
QPixmap pic;
// Load icon
auto res = RES->RequestResource(0, aPkgName, SpkResource::ResourceType::AppIcon, aIcon);
if(res.status == SpkResource::ResourceStatus::Ready)
{
if(pic.loadFromData(res.data))
mAppIcon->setPixmap(pic.scaled(IconSize,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
else
{
mAppIcon->setPixmap(mBrokenImg);
RES->PurgeCachedResource(aPkgName, SpkResource::ResourceType::AppIcon, 0);
}
}
// Load screenshots. Screenshots have id starting with 1.
if(aScreenshots.isEmpty())
return;
else
{
auto count = aScreenshots.size();
mImgViewer->SetImageTotal(count);
if(count > mScreenshotPreviews.size())
{
auto from = mScreenshotPreviews.size(), to = count - mScreenshotPreviews.size();
for(int i = 0; i <= to; i++)
{
auto wid = new SpkClickLabel;
wid->setProperty("shotId", from + i + 1);
wid->setFixedHeight(200);
wid->setCursor(Qt::PointingHandCursor);
connect(wid, &SpkClickLabel::Pressed, this, &SpkPageAppDetails::ImageClicked);
mScreenshotPreviews.append(wid);
mScreenshotLay->addWidget(wid);
}
}
}
int shotId = 0;
for(auto &i : aScreenshots)
{
shotId++;
res = RES->RequestResource(shotId, aPkgName, SpkResource::ResourceType::AppScreenshot, i,
shotId);
auto preview = mScreenshotPreviews[shotId - 1];
preview->setVisible(true);
if(res.status == SpkResource::ResourceStatus::Ready)
{
if(pic.loadFromData(res.data))
{
mAppImages[shotId] = pic;
mImgViewer->SetPixmap(shotId, &mAppImages[shotId]);
preview->setPixmap(pic.scaledToHeight(200, Qt::SmoothTransformation));
}
else
{
mAppImages[shotId] = mBrokenImg;
RES->PurgeCachedResource(aPkgName, SpkResource::ResourceType::AppScreenshot, 0);
}
}
else
{
preview->setPixmap(mIconLoading);
}
}
// TODO: tags
}
void SpkPageAppDetails::SetWebsiteLink(QString url)
{
mWebsite->setText(QString("<a href=\"%1\">%2</a>").arg(url, tr("Website link")));
}
void SpkPageAppDetails::SetPackagePath(QString url)
{
mPkgPath = url;
}
SpkPageAppDetails::SpkPageAppDetails(QWidget *parent) : SpkPageBase(parent),
mBrokenImg(QIcon(":/icons/broken-icon.svg").pixmap(SpkAppItem::IconSize_)),
mIconLoading(QIcon(":/icons/loading-icon.svg").pixmap(SpkAppItem::IconSize_))
{
mMainArea = new QScrollArea;
mMainArea->setWidgetResizable(true);
mMainArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mMainLay = new QVBoxLayout(this);
mMainLay->addWidget(mMainArea);
mBottomBar = new QWidget;
mMainLay->addWidget(mBottomBar);
mDetailsLay = new QVBoxLayout(mMainArea);
mDetailsLay->setSizeConstraint(QLayout::SetMinAndMaxSize);
mAppIcon = new QLabel;
mAppTitle = new QLabel;
mAppTitle->setObjectName("styDetTitle");
mAppTitle->setWordWrap(true);
mAppDescription = new QLabel;
mAppDescription->setObjectName("styDetDesc");
mAppDescription->setWordWrap(true);
mAppShortDesc = new QLabel;
mAppShortDesc->setObjectName("styDetDesc");
mAppShortDesc->setWordWrap(true);
// NOTE: Seems Qt have trouble dealing with wrapped text here. Removing the following operations
// to mAppShortDesc will result in broken layout. Very possible that it's a Qt bug.
mAppShortDesc->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
mAppShortDesc->setMinimumWidth(100);
mVersion = new QLabel;
mVersion->setWordWrap(true);
mWebsite = new QLabel;
mPkgName = new QLabel;
mPkgName->setObjectName("styDetPkg");
mPkgName->setWordWrap(true);
mTitleLay = new QVBoxLayout;
mTitleLay->setAlignment(Qt::AlignTop);
mTitleLay->addWidget(mAppTitle);
mTitleLay->addWidget(mVersion);
mTitleLay->addWidget(mAppShortDesc);
mTitleLay->addWidget(mPkgName);
mTitleLay->addWidget(mWebsite);
mTitleLay->setSpacing(0);
mIconTitleLay = new QHBoxLayout;
mIconTitleLay->setAlignment(Qt::AlignLeft);
mIconTitleLay->addWidget(mAppIcon);
mIconTitleLay->addSpacing(15);
mIconTitleLay->addLayout(mTitleLay);
mIconTitleWidget = new QWidget;
mIconTitleWidget->setLayout(mIconTitleLay);
mAuthor = new SpkDetailEntry;
mAuthor->SetTitle(tr("Author"));
mContributor = new SpkDetailEntry;
mContributor->SetTitle(tr("Contributor"));
// mSite = new SpkDetailEntry;
// mSite->SetTitle(tr("Website"));
mArch = new SpkDetailEntry;
mArch->SetTitle(tr("Architecture"));
mSize = new SpkDetailEntry;
mSize->SetTitle(tr("Size"));
mDetailLay = new SpkStretchLayout;
mDetailLay->setSpacing(12);
mDetailLay->addWidget(mAuthor);
mDetailLay->addWidget(mContributor);
mDetailLay->addWidget(mSize);
mDetailLay->addWidget(mArch);
// mDetailLay->addWidget(mSite);
// mDetailWidget = new QWidget;
// mDetailWidget->setLayout(mDetailLay);
// mDetailWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
mDetailsLay->setAlignment(Qt::AlignTop);
mDetailsLay->addWidget(mIconTitleWidget);
mDetailsLay->addLayout(mDetailLay);
mDetailsLay->addWidget(mAppDescription);
// mMainLay->addStretch();
mScreenshotLay = new QHBoxLayout;
mScreenshotArea = new QScrollArea;
mWid4ShotArea = new QWidget;
mWid4ShotArea->setLayout(mScreenshotLay);
mScreenshotArea->setWidget(mWid4ShotArea);
mScreenshotArea->setWidgetResizable(true);
mScreenshotArea->setFixedHeight(230);
mScreenshotArea->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
mDetailsLay->addWidget(mScreenshotArea);
mWid4MainArea = new QWidget;
mWid4MainArea->setLayout(mDetailsLay);
mMainArea->setWidget(mWid4MainArea);
mWebsite->setTextFormat(Qt::RichText);
mWebsite->setOpenExternalLinks(true);
// Bottom bar buttons
mBottomBarLay = new QHBoxLayout;
mBottomBar->setLayout(mBottomBarLay);
mBtnDownload = new QPushButton;
mBtnDownload->setText(tr("Download"));
// mBtnInstall = new QPushButton;
// mBtnInstall->setText(tr("Install"));
mBtnUninstall = new QPushButton;
mBtnUninstall->setText(tr("Uninstall"));
mBtnRequestUpdate = new QPushButton;
mBtnRequestUpdate->setText(tr("Request Update"));
mBtnReport = new QPushButton;
mBtnReport->setText(tr("Report"));
mBottomBarLay->addStretch();
mBottomBarLay->addWidget(mBtnDownload);
// mBottomBarLay->addWidget(mBtnInstall);
mBottomBarLay->addWidget(mBtnUninstall);
mBottomBarLay->addWidget(mBtnRequestUpdate);
mBottomBarLay->addWidget(mBtnReport);
mImgViewer = new SpkImgViewer;
mImgViewer->setVisible(false);
connect(mBtnDownload, &QPushButton::clicked,
[=](){ emit RequestDownload(mAppTitle->text(), mPkgName->text(),
"/store/reading/youdao-dict/youdao-dict_6.0.0-0~ubuntu_amd64.deb");
});
}
SpkPageAppDetails::~SpkPageAppDetails()
{
delete mImgViewer;
}
void SpkPageAppDetails::ResourceAcquisitionFinished(int id, ResourceResult result)
{
QPixmap img;
// qDebug() << "PageAppDetails: Resource" << id << "acquired";
if(!id)
{
// id == 0, icon
if(result.status == SpkResource::ResourceStatus::Ready)
{
if(img.loadFromData(result.data))
mAppIcon->setPixmap(img.scaled(SpkAppItem::IconSize_,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
else
mAppIcon->setPixmap(mBrokenImg);
}
else if(result.status == SpkResource::ResourceStatus::Failed)
{
mAppIcon->setPixmap(mBrokenImg);
RES->PurgeCachedResource(mPkgName->text(), SpkResource::ResourceType::AppIcon, 0);
}
}
else
{
auto preview = mScreenshotPreviews[id - 1];
preview->setVisible(true);
if(result.status == SpkResource::ResourceStatus::Ready)
{
if(img.loadFromData(result.data))
{
mAppImages[id] = img;
mImgViewer->SetPixmap(id, &mAppImages[id]);
mScreenshotPreviews[id - 1]->setPixmap(img.scaledToHeight(200, Qt::SmoothTransformation));
}
else
{
mImgViewer->SetPixmap(id, &mBrokenImg);
mScreenshotPreviews[id - 1]->setPixmap(mBrokenImg);
}
}
else if(result.status == SpkResource::ResourceStatus::Failed)
{
mImgViewer->SetPixmap(id, &mBrokenImg);
mScreenshotPreviews[id - 1]->setPixmap(mBrokenImg);
RES->PurgeCachedResource(mPkgName->text(), SpkResource::ResourceType::AppIcon, 0);
}
}
}
void SpkPageAppDetails::Activated()
{
RES->Acquire(this, false);
for(auto &i : mScreenshotPreviews)
i->setVisible(false);
mImgViewer->Clear();
}
void SpkPageAppDetails::ImageClicked()
{
mImgViewer->ShowWithImage(sender()->property("shotId").toInt());
}
SpkDetailEntry::SpkDetailEntry(QWidget *parent) : QWidget(parent)
{
setLayout(&mLay);
mLay.addWidget(&mTitle);
mLay.addWidget(&mField);
mTitle.setAlignment(Qt::AlignLeft);
mField.setAlignment(Qt::AlignRight);
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
setMinimumWidth(300);
setAutoFillBackground(true);
}
}

View File

@@ -1,181 +0,0 @@
#include "page/spkpageapplist.h"
#include "spkutils.h"
#include "spkuimsg.h"
namespace SpkUi
{
SpkPageAppList::SpkPageAppList(QWidget *parent) : SpkPageBase(parent)
{
mLoadingIcon = new QPixmap(QIcon(":/icons/loading-icon.svg").pixmap(SpkAppItem::IconSize_));
mBrokenIcon = new QPixmap(QIcon(":/icons/broken-icon.svg").pixmap(SpkAppItem::IconSize_));
mAppsWidget = new QWidget;
mAppsArea = new QScrollArea(this);
mMainLay = new QVBoxLayout(this);
mItemLay = new SpkStretchLayout(mAppsWidget);
mPageSwitchWidget = new QWidget;
mPageSwitchLay = new QHBoxLayout(mPageSwitchWidget);
mBtnPgUp = new QPushButton;
mBtnPgDown = new QPushButton;
mBtnGotoPage = new QPushButton;
mPageInput = new QLineEdit;
mPageValidator = new QIntValidator(mPageInput);
mPageIndicator = new QLabel;
mPageValidator->setRange(1, 99);
mPageInput->setFixedWidth(50);
mPageInput->setValidator(mPageValidator);
mBtnGotoPage->setText(tr("Goto"));
mBtnPgUp->setText(tr("Previous"));
mBtnPgDown->setText(tr("Next"));
mBtnGotoPage->setFocusPolicy(Qt::NoFocus);
mBtnPgDown->setFocusPolicy(Qt::NoFocus);
mBtnPgUp->setFocusPolicy(Qt::NoFocus);
mPageSwitchLay->addWidget(mPageIndicator);
mPageSwitchLay->addStretch();
mPageSwitchLay->addWidget(mPageInput);
mPageSwitchLay->addWidget(mBtnGotoPage);
mPageSwitchLay->addWidget(mBtnPgUp);
mPageSwitchLay->addWidget(mBtnPgDown);
mAppsArea->setWidget(mAppsWidget);
mAppsArea->setWidgetResizable(true);
mMainLay->addWidget(mAppsArea);
mMainLay->addWidget(mPageSwitchWidget);
setLayout(mMainLay);
connect(mBtnPgUp, &QPushButton::clicked, this, &SpkPageAppList::PageUp);
connect(mBtnPgDown, &QPushButton::clicked, this, &SpkPageAppList::PageDown);
connect(mBtnGotoPage, &QPushButton::clicked, this, &SpkPageAppList::GotoPage);
}
void SpkPageAppList::AddApplicationEntry(QString name, QString pkgName, QString description,
QString iconUrl, int appId)
{
auto item = new SpkAppItem(appId, this);
auto id = mAppItemList.size();
connect(item, &SpkAppItem::clicked, this, &SpkPageAppList::ApplicationClicked);
item->SetTitle(name);
item->SetDescription(description);
item->setProperty("pkg_name", pkgName);
auto iconRes = RES->RequestResource(id, pkgName, SpkResource::ResourceType::AppIcon,
iconUrl, 0);
QPixmap icon;
if(iconRes.status == SpkResource::ResourceStatus::Ready)
{
if(icon.loadFromData(iconRes.data))
item->SetIcon(icon.scaled(SpkAppItem::IconSize_,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
else
{
item->SetIcon(*mBrokenIcon);
RES->PurgeCachedResource(pkgName, SpkResource::ResourceType::AppIcon, 0);
}
}
else
item->SetIcon(*mLoadingIcon);
mAppItemList.append(item);
mItemLay->addWidget(item);
}
void SpkPageAppList::ClearAll()
{
QWidget *itm;
QLayoutItem *layitm;
while((layitm = mItemLay->takeAt(0)))
{
itm = layitm->widget();
itm->hide();
itm->deleteLater();
}
mAppItemList.clear();
mAppsArea->verticalScrollBar()->setValue(0);
}
void SpkPageAppList::ResourceAcquisitionFinished(int id, ResourceResult result)
{
QPixmap icon;
// qDebug() << "PageAppList: Resource" << id << "acquired";
auto item = mAppItemList[id];
if(result.status == SpkResource::ResourceStatus::Ready)
{
if(icon.loadFromData(result.data))
item->SetIcon(icon.scaled(SpkAppItem::IconSize_,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
else
item->SetIcon(*mBrokenIcon);
}
else if(result.status == SpkResource::ResourceStatus::Failed)
{
item->SetIcon(*mBrokenIcon);
RES->PurgeCachedResource(item->property("pkg_name").toString(),
SpkResource::ResourceType::AppIcon, 0);
}
}
void SpkPageAppList::SetPageStatus(int total, int current, int itemCount, QString &keyword)
{
mCurrentPage = current;
mKeyword = keyword;
mPageIndicator->setText(tr("Page %1 / %2, %3 apps in total")
.arg(current).arg(total).arg(itemCount));
mBtnPgUp->setDisabled(current == 1);
mBtnPgDown->setDisabled(total == current || total == 1);
mBtnGotoPage->setDisabled(total == 1);
mPageValidator->setTop(total);
}
void SpkPageAppList::DisablePageSwitchers()
{
mBtnPgDown->setDisabled(true);
mBtnPgUp->setDisabled(true);
mBtnGotoPage->setDisabled(true);
}
void SpkPageAppList::PageUp()
{
DisablePageSwitchers();
if(mKeyword.isEmpty())
emit SwitchListPage(mCategoryId, mCurrentPage - 1);
else
emit SwitchSearchPage(mKeyword, mCurrentPage - 1);
}
void SpkPageAppList::PageDown()
{
DisablePageSwitchers();
if(mKeyword.isEmpty())
emit SwitchListPage(mCategoryId, mCurrentPage + 1);
else
emit SwitchSearchPage(mKeyword, mCurrentPage + 1);
}
void SpkPageAppList::GotoPage()
{
if(mPageInput->text().isEmpty())
return SpkUiMessage::SendStoreNotification(tr("Please enter page number to go to!"));
int page = mPageInput->text().toInt();
if(page > mPageValidator->top())
return SpkUiMessage::SendStoreNotification(tr("Page %1 is not a valid page number!")
.arg(page));
DisablePageSwitchers();
if(mKeyword.isEmpty())
emit SwitchListPage(mCategoryId, page);
else
emit SwitchSearchPage(mKeyword, page);
}
void SpkPageAppList::Activated()
{
RES->Acquire(this, false);
}
}

View File

@@ -1,41 +0,0 @@
#include "page/spkpagebase.h"
/*
* Documentation on
* How to Add a New Page to Main Window Side Bar
*
* 1. Derive your page widget class from SpkPageBase (reference implementation
* in SpkPageSettings) and add them to CMakeLists
*
* 2. Add the ID for the page in enum SpkUi::SpkStackedPages (in spkmainwindow.h)
* and add it as a resource context if needed
*
* 3. Include the page's header file in spkmainwindow.h and add a pointer to it in
* SpkUi::SpkMainWidget
*
* 4. Add a tree item or icon button for the corresponding page inside
* SpkUi::SpkMainWidget, and initialize it in SpkUi::SpkMainWidget::SpkMainWidget.
* Take references of existing entries, and write similar code close to each other
* to make the source look nice. Don't forget to add the item to the UI.
*
* 5. Make the linkage between the page and the sidebar item at the end of
* SpkUi::SpkMainWidget::SpkMainWidget().
*
*/
SpkPageBase::SpkPageBase(QWidget *parent) : QWidget(parent)
{
}
void SpkPageBase::ResourceAcquisitionFinished(int id, ResourceResult result)
{
Q_UNUSED(id);
Q_UNUSED(result);
}
void SpkPageBase::Activated()
{
; // Do nothing
}

View File

@@ -1,214 +0,0 @@
#include "page/spkpagedownloads.h"
#include "pkgs/spkpkgmgrbase.h"
#include "spkuimsg.h"
#include "spkutils.h"
SpkUi::SpkPageDownloads::SpkPageDownloads(QWidget *parent) :
SpkPageBase(parent)
{
mMainLay = new QVBoxLayout(this);
mLayEntries = new QVBoxLayout;
mScrollWidget = new QWidget;
mScrollArea = new QScrollArea(this);
mLayEntries->setAlignment(Qt::AlignTop);
mScrollWidget->setLayout(mLayEntries);
mScrollArea->setWidget(mScrollWidget);
mScrollArea->setWidgetResizable(true);
mMainLay->addWidget(mScrollArea);
setLayout(mMainLay);
mDownloadMgr = new SpkDownloadMgr(this);
connect(mDownloadMgr, &SpkDownloadMgr::DownloadProgressed,
this, &SpkPageDownloads::DownloadProgress);
mNextDownloadId = 0;
mCurrentStatus = Idle;
connect(mDownloadMgr, &SpkDownloadMgr::DownloadStopped,
this, &SpkPageDownloads::DownloadStopped, Qt::QueuedConnection);
connect(PKG, &SpkPkgMgrBase::ReportInstallResult,
this, &SpkPageDownloads::InstallationEnded);
}
SpkUi::SpkPageDownloads::~SpkPageDownloads()
{
// TODO
}
void SpkUi::SpkPageDownloads::DownloadProgress(qint64 downloadedBytes, qint64 totalBytes, int id)
{
if(!totalBytes)
return;
if(mCurrentStatus == Waiting && totalBytes)
{
mCurrentStatus = Downloading;
mEntries[id]->SetTotalBytes(totalBytes);
mEntries[id]->SetStatus(SpkDownloadEntry::Downloading);
}
mEntries[id]->Progress(downloadedBytes);
}
void SpkUi::SpkPageDownloads::AddDownloadTask(QString name, QString pkgName, QString path)
{
// Add a new download entry into the UI
auto entry = new SpkDownloadEntry;
auto iconData = RES->CacheLookup(pkgName, SpkResource::ResourceType::AppIcon, 0);
auto id = mNextDownloadId;
QPixmap icon;
if(iconData.status != SpkResource::ResourceStatus::Ready || !icon.loadFromData(iconData.data))
icon.load(":/icons/broken-icon.svg");
entry->SetBasicInfo(name, icon, mDownloadMgr->GetDestFilePath(path));
entry->SetStatus(SpkDownloadEntry::Waiting);
entry->setProperty("entryId", id);
entry->setProperty("path", path);
mNextDownloadId++;
mEntries[id] = entry;
mLayEntries->addWidget(entry);
connect(entry, &SpkDownloadEntry::Action,
this, &SpkPageDownloads::EntryAction);
NewDownloadTask(id, path);
}
void SpkUi::SpkPageDownloads::DownloadStopped(SpkDownloadMgr::TaskResult status, int id)
{
switch(status)
{
case SpkDownloadMgr::Success:
mEntries[id]->SetStatus(SpkDownloadEntry::ToBeInstalled);
break;
case SpkDownloadMgr::FailCannotCreateFile:
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
tr("Cannot create download file. Download failed."));
break;
case SpkDownloadMgr::FailNoVaibleServer:
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
tr("Connection unstable or server failure. Download failed."));
break;
case SpkDownloadMgr::FailCancel:
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
tr("This download was cancelled."));
break;
case SpkDownloadMgr::Fail:
mEntries[id]->SetStatus(SpkDownloadEntry::DownloadFailed,
tr("Unknown error. Download failed."));
break;
}
if(status == SpkDownloadMgr::Success)
SpkUiMessage::SendDesktopNotification(
tr("App \"%1\" downloaded, and ready to install.").arg(mEntries[id]->GetTaskName()));
else if(status != SpkDownloadMgr::FailCancel)
SpkUiMessage::SendDesktopNotification(
tr("Error occurred downloading \"%1\".").arg(mEntries[id]->GetTaskName()));
// Continue next download task
if(!mWaitingDownloads.isEmpty())
{
auto nextTask = mWaitingDownloads.dequeue();
auto nextEntry = mEntries[nextTask.first];
nextEntry->SetStatus(SpkDownloadEntry::Starting);
mDownloadMgr->StartNewDownload(nextTask.second, nextTask.first);
mCurrentStatus = Waiting;
}
else
{
mCurrentStatus = Idle;
}
}
void SpkUi::SpkPageDownloads::EntryAction(SpkDownloadEntry::EntryAction act)
{
SpkDownloadEntry *entry = static_cast<SpkDownloadEntry*>(sender());
auto id = entry->property("entryId").toInt();
switch(act)
{
case SpkDownloadEntry::AbortDownload:
mDownloadMgr->CancelCurrentDownload(); // Only one task at a time so simply abort download
break;
case SpkDownloadEntry::RetryDownload:
mLayEntries->removeWidget(entry); // Move to list tail
mLayEntries->addWidget(entry);
NewDownloadTask(id, entry->property("path").toString());
entry->SetStatus(SpkDownloadEntry::Waiting);
break;
case SpkDownloadEntry::StartInstall:
switch(PKG->ExecuteInstallation(entry->GetFilePath(), id))
{
case SpkPkgMgrBase::Succeeded:
entry->SetStatus(SpkDownloadEntry::Installing);
break;
case SpkPkgMgrBase::Failed:
entry->SetStatus(SpkDownloadEntry::InstallFailed,
tr("Failed to start installation."));
break;
default: break;
}
break;
case SpkDownloadEntry::RemoveEntry:
mLayEntries->removeWidget(entry);
mEntries.remove(id);
for(auto i = mWaitingDownloads.begin(); i != mWaitingDownloads.end(); i++)
{
if(i->first == id)
{
mWaitingDownloads.erase(i);
break;
}
}
entry->setVisible(false);
entry->deleteLater();
break;
}
}
void SpkUi::SpkPageDownloads::InstallationEnded(int id,
SpkPkgMgrBase::PkgInstallResult result,
int exitCode)
{
if(result == SpkPkgMgrBase::Succeeded)
{
mEntries[id]->SetStatus(SpkDownloadEntry::Installed);
}
else
{
mEntries[id]->SetStatus(SpkDownloadEntry::InstallFailed,
tr("Install failed, exit code: %1.").arg(exitCode));
}
}
void SpkUi::SpkPageDownloads::NewDownloadTask(int id, QString downloadPath)
{
if(mCurrentStatus != Idle)
mWaitingDownloads.enqueue({ id, downloadPath }); // Queue download task for future
else
{
auto nextEntry = mEntries[id];
nextEntry->SetStatus(SpkDownloadEntry::Starting);
mCurrentStatus = Waiting;
if(!mDownloadMgr->StartNewDownload(downloadPath, id)) // Initiate a download task when idle
{
// If fails to start then try next one. Emitting this signal causes
// SpkPageDownloads::DownloadStopped to be activated and thus tries next item in queue
emit mDownloadMgr->DownloadStopped(SpkDownloadMgr::FailNoVaibleServer, id);
}
}
}

View File

@@ -1,50 +0,0 @@
#include <QDesktopServices>
#include "page/spkpagehome.h"
#include "spkabout.h"
#include "gitver.h"
SpkUi::SpkPageHome::SpkPageHome(QWidget *parent) :
SpkPageBase(parent)
{
ui = new Ui::SpkHomepage;
ui->setupUi(this);
SetupUi();
}
void SpkUi::SpkPageHome::LinkActivated(QString s)
{
QDesktopServices::openUrl(QUrl(s));
}
void SpkUi::SpkPageHome::SetupUi()
{
ui->lblIcon->setPixmap(QIcon(":/icons/spark-store.svg").pixmap(QSize(128, 128)));
ui->hlayTitle->setAlignment(Qt::AlignHCenter);
ui->lblVersion->setText(ui->lblVersion->text().arg(GitVer::DescribeTags()));
ui->lblNewAnnouncement->setVisible(false);
// Click event will propagate to the main window and cause the window to move when
// mouse enters the zoom & move detection area. Disable mouse event propagation.
ui->lblAuthor->setAttribute(Qt::WA_NoMousePropagation, true);
ui->widReloadCategory->setVisible(false);
ui->widReloadCategory->setAttribute(Qt::WA_StyledBackground);
ui->lblCategoryErrIcon->setPixmap(QIcon::fromTheme("dialog-error").pixmap(QSize(32, 32)));
connect(ui->lblAuthor, &QLabel::linkActivated,
this, &SpkPageHome::LinkActivated);
connect(ui->btnSubmit, &QPushButton::clicked,
[&](){ LinkActivated("https://upload.deepinos.org"); });
connect(ui->btnFeedback, &QPushButton::clicked,
[&](){ LinkActivated("https://www.deepinos.org/t/spark-feedback"); });
connect(ui->btnDonation, &QPushButton::clicked,
[&](){ LinkActivated("https://spark.deepinos.org.cn/"); });
connect(ui->btnAbout, &QPushButton::clicked,
[&](){ SpkAbout::Show(); });
}

View File

@@ -1,225 +0,0 @@
#include <QtConcurrent/QtConcurrentRun>
#include <QMutexLocker>
#include <QFutureWatcher>
#include "spkutils.h"
#include "page/spkpagesettings.h"
#include "spkmsgbox.h"
namespace SpkUi
{
SpkPageSettings::SpkPageSettings(QWidget *parent) :
SpkPageBase(parent)
{
mMainArea = new QScrollArea();
mMainLay = new QVBoxLayout(this);
mSettingsWidget = new QWidget(this);
ui = new Ui::SpkUiSettings;
ui->setupUi(mSettingsWidget);
mMainLay->addWidget(mMainArea);
mMainArea->setWidget(mSettingsWidget);
mMainArea->setWidgetResizable(true);
CFG->BindField("url/repo", &this->mRepoListUrl,
"https://d.store.deepinos.org.cn/store/server.list");
mBytesDownloads = mBytesResource = -1;
connect(&mFwResourceClean, &QFutureWatcher<void>::finished,
this, &SpkPageSettings::CleanedResource);
connect(&mFwResourceCount, &QFutureWatcher<void>::finished,
this, &SpkPageSettings::CountFinishResource);
connect(&mFwDownloadClean, &QFutureWatcher<void>::finished,
this, &SpkPageSettings::CleanedDownload);
connect(&mFwDownloadCount, &QFutureWatcher<void>::finished,
this, &SpkPageSettings::CountFinishDownload);
connect(ui->btnViewDownloadedContent, &QPushButton::clicked,
this, &SpkPageSettings::on_btnViewDownloadedContent_clicked);
connect(ui->btnViewResourceCache, &QPushButton::clicked,
this, &SpkPageSettings::on_btnViewResourceCache_clicked);
connect(ui->btnCleanDownloadedContent, &QPushButton::clicked,
this, &SpkPageSettings::on_btnCleanDownloadedContent_clicked);
connect(ui->btnCleanResourceCache, &QPushButton::clicked,
this, &SpkPageSettings::on_btnCleanResourceCache_clicked);
SetupUi();
}
SpkPageSettings::~SpkPageSettings()
{
delete mSettingsWidget;
}
void SpkPageSettings::SetupUi()
{
ui->lblSettingsTitle->setObjectName("styConfTitle");
ui->lblCleanup->setObjectName("styConfTitle");
ui->lblAdvanced->setObjectName("styConfTitle");
connect(ui->btnSave, &QPushButton::clicked,
this, &SpkPageSettings::SaveConfiguration);
}
void SpkPageSettings::ReadConfiguration()
{
ui->spnConcurrentResDownloads->setValue(CFG->ReadField("resource/concurrent", 5).toInt());
ui->edtApiUrl->setText(CFG->ReadField("url/api", "").toString());
ui->edtResourceUrl->setText(CFG->ReadField("url/res", "").toString());
ui->edtResourceCachePath->setText(CFG->ReadField("dirs/cache", "").toString());
ui->edtDownloadPath->setText(CFG->ReadField("dirs/download", "").toString());
ui->edtDownloadServers->setPlainText(CFG->ReadField("download/servers", "").toString());
ui->edtQssPath->setText(CFG->ReadField("internal/qss_path", "").toString());
ui->edtRepoListUrl->setText(CFG->ReadField("url/repo", "").toString());
ui->cmbLightDarkTheme->setCurrentIndex(CFG->ReadField("ui/theme", 0).toInt());
}
void SpkPageSettings::SaveConfiguration()
{
CFG->SetSettings("resource/concurrent", ui->spnConcurrentResDownloads->value());
CFG->SetField("url/api", ui->edtApiUrl->text());
CFG->SetField("url/res", ui->edtResourceUrl->text());
CFG->SetSettings("dirs/cache", ui->edtResourceCachePath->text());
CFG->SetField("dirs/download", ui->edtDownloadPath->text());
CFG->SetSettings("internal/qss_path", ui->edtQssPath->text());
CFG->SetField("url/repo", ui->edtRepoListUrl->text());
if(!CFG->SetField("download/servers", ui->edtDownloadServers->toPlainText()))
SpkMsgBox::StaticExec(tr("Cannot change distribution servers.\n"
"There's probably still downloads going on."),
tr("Cannot set distribution server"),
QMessageBox::Warning);
if(!CFG->SetField("ui/theme", ui->cmbLightDarkTheme->currentIndex()))
SpkMsgBox::StaticExec(tr("Auto mode can only be used when DDE plugin is loaded.\n"
"Option change is not applied."),
tr("Cannot set theme mode"),
QMessageBox::Warning);
}
void SpkPageSettings::CountCleaning()
{
ui->lblSizeDownloadedContent->setText(tr("Counting..."));
ui->lblSizeResourceCache->setText(tr("Counting..."));
auto futureDownload = QtConcurrent::run([&]()
{
QDirIterator itr(ui->edtDownloadPath->text().replace('*', QDir::homePath()),
QDirIterator::Subdirectories);
if(mMutDownload.tryLock(0))
{
int64_t size = 0;
while(itr.hasNext())
{
QFile f(itr.next());
size += f.size();
}
mBytesDownloads = size;
mMutDownload.unlock();
}
});
auto futureResource = QtConcurrent::run([&]()
{
QDirIterator itr(ui->edtResourceCachePath->text().replace('*', QDir::homePath()),
QDirIterator::Subdirectories);
if(mMutResource.tryLock((0)))
{
int64_t size = 0;
while(itr.hasNext())
{
QFile f(itr.next());
size += f.size();
}
mBytesResource = size;
mMutResource.unlock();
}
});
mFwDownloadCount.setFuture(futureDownload);
mFwResourceCount.setFuture(futureResource);
}
void SpkPageSettings::CleanedResource()
{
ui->lblSizeResourceCache->setText(tr("Cleaned"));
}
void SpkPageSettings::CleanedDownload()
{
ui->lblSizeDownloadedContent->setText(tr("Cleaned"));
}
void SpkPageSettings::Activated()
{
ReadConfiguration();
CountCleaning();
}
void SpkPageSettings::CountFinishResource()
{
if(mBytesResource >= 0)
ui->lblSizeResourceCache->setText(SpkUtils::BytesToSize(mBytesResource));
}
void SpkPageSettings::CountFinishDownload()
{
if(mBytesDownloads >= 0)
ui->lblSizeDownloadedContent->setText(SpkUtils::BytesToSize(mBytesDownloads));
}
void SpkPageSettings::on_btnViewResourceCache_clicked()
{
QDesktopServices::openUrl(ui->edtResourceCachePath->text().replace('*', QDir::homePath()));
}
void SpkPageSettings::on_btnViewDownloadedContent_clicked()
{
QDesktopServices::openUrl(ui->edtDownloadPath->text().replace('*', QDir::homePath()));
}
void SpkPageSettings::on_btnCleanResourceCache_clicked()
{
ui->lblSizeResourceCache->setText(tr("Cleaning..."));
auto future = QtConcurrent::run([&]()
{
QDirIterator itr(ui->edtResourceCachePath->text().replace('*', QDir::homePath()),
QDirIterator::Subdirectories);
if(mMutDownload.tryLock(0))
{
int64_t size = 0;
while(itr.hasNext())
{
QFile f(itr.next());
f.remove();
}
mBytesDownloads = size;
mMutDownload.unlock();
}
});
mFwResourceClean.setFuture(future);
}
void SpkPageSettings::on_btnCleanDownloadedContent_clicked()
{
ui->lblSizeDownloadedContent->setText(tr("Cleaning..."));
auto futureDownload = QtConcurrent::run([&]()
{
QDirIterator itr(ui->edtDownloadPath->text().replace('*', QDir::homePath()),
QDirIterator::Subdirectories);
if(mMutDownload.tryLock(0))
{
int64_t size = 0;
while(itr.hasNext())
{
QFile f(itr.next());
f.remove();
}
mBytesDownloads = size;
mMutDownload.unlock();
}
});
mFwDownloadClean.setFuture(futureDownload);
}
}

View File

@@ -1,165 +0,0 @@
#include <QApplication>
#include "spkabout.h"
#include "inc/page/spkpageuitest.h"
#include "spkpopup.h"
#include "spkui_general.h"
#include "pkgs/spkpkgmgrbase.h"
SpkUi::SpkPageUiTest::SpkPageUiTest(QWidget *parent) : QSplitter(parent)
{
setObjectName("spk_pg_qsstest");
TextStylesheet = new QTextEdit(this);
TextStylesheet->setObjectName("spk_pg_qsstest_qsstext");
TextStylesheet->setPlainText(SpkUi::CurrentStylesheet);
BtnApply = new QPushButton(this);
BtnApply->setObjectName("spk_pg_qsstest_btnapply");
BtnApply->setText("Apply");
connect(BtnApply, &QPushButton::pressed, this, &SpkPageUiTest::SetStylesheet);
BtnFetch = new QPushButton(this);
BtnFetch->setObjectName("spk_pg_qsstest_btnfetch");
BtnFetch->setText("Fetch Stylesheet");
connect(BtnFetch, &QPushButton::pressed, this, &SpkPageUiTest::FetchStylesheet);
HLayInputBtns = new QHBoxLayout;
HLayInputBtns->setObjectName("spk_pg_qsstest_hlay_inputbtns");
HLayInputBtns->addWidget(BtnFetch);
HLayInputBtns->addWidget(BtnApply);
Btn = new QPushButton(this);
Btn->setObjectName("spk_pg_qsstest_button");
Btn->setText("TestButton");
Chk = new QCheckBox(this);
Chk->setObjectName("spk_pg_qsstest_checkbox");
Chk->setText("CheckBox");
Rad = new QRadioButton(this);
Rad->setObjectName("spk_pg_qsstest_radiobtn");
Rad->setText("RadioButton");
Loading = new SpkLoading(this);
Loading->setObjectName("spk_pg_qsstest_loading");
Loading->start();
Prog = new QProgressBar(this);
Prog->setObjectName("spk_pg_qsstest_prog");
Prog->setValue(65);
Prog->setRange(0, 100);
AppItem = new SpkAppItem(0, this);
AppItem->setObjectName("spk_pg_qsstest_appitem");
AppItem->SetTitle("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
AppItem->SetDescription("Nam vehicula lacus vitae leo fermentum efficitur. "
"Phasellus finibus risus id aliquam pulvinar.");
AppItem->SetIcon(QIcon::fromTheme("dialog-information").pixmap(72, 72));
Detail1 = new SpkDetailEntry; Detail1->SetTitle("Foo"); Detail1->SetValue("1");
Detail2 = new SpkDetailEntry; Detail2->SetTitle("Foo"); Detail2->SetValue("1");
Detail3 = new SpkDetailEntry; Detail3->SetTitle("Foo"); Detail3->SetValue("1");
DetailsLay = new SpkStretchLayout;
DetailsLay->addWidget(Detail1);
DetailsLay->addWidget(Detail2);
DetailsLay->addWidget(Detail3);
DetailsWidget = new QWidget;
DetailsWidget->setLayout(DetailsLay);
PopupText = new QLineEdit(this);
PopupText->setObjectName("spk_pg_qsstest_poptext");
PopupText->setText("Hello, world");
ShowPopup = new QPushButton(this);
ShowPopup->setText("Show Popup");
connect(ShowPopup, &QPushButton::clicked, this, &SpkPageUiTest::ShowPopupSlot);
ShowAbout = new QPushButton(this);
ShowAbout->setText("Show About Dialog");
connect(ShowAbout, &QPushButton::clicked, [](){ SpkAbout::Show(); });
ShowPkgmgr = new QPushButton(this);
ShowPkgmgr->setText("Show Install Menu");
connect(ShowPkgmgr, &QPushButton::clicked, [=](){ SpkPkgMgrBase::Instance()->ExecuteInstallation(PopupText->text(), 0); });
SlideV = new QSlider(this);
SlideV->setObjectName("spk_pg_qsstest_slider_v");
SlideV->setOrientation(Qt::Vertical);
SlideV->setMaximum(1000);
SlideV->setMinimum(0);
SlideH = new QSlider(this);
SlideH->setObjectName("spk_pg_qsstest_slider_h");
SlideH->setOrientation(Qt::Horizontal);
SlideH->setMaximum(1000);
SlideH->setMinimum(0);
IconBtn = new SpkIconButton(this);
IconBtn->setObjectName("spk_pg_qsstest_iconbtn");
IconBtn->SetIcon(QIcon(":/icons/settings.svg"), QSize{ 16, 16 });
VLayTestWidgets = new QVBoxLayout;
VLayTestWidgets->setObjectName("spk_pg_qsstest_vlay_btn");
VLayTestWidgets->addWidget(Btn);
VLayTestWidgets->addWidget(Chk);
VLayTestWidgets->addWidget(Rad);
VLayTestWidgets->addWidget(IconBtn);
VLayTestWidgets->addWidget(Loading);
VLayTestWidgets->addWidget(PopupText);
VLayTestWidgets->addWidget(ShowPopup);
VLayTestWidgets->addWidget(ShowAbout);
VLayTestWidgets->addWidget(ShowPkgmgr);
VLayTestWidgets->addWidget(AppItem);
VLayTestWidgets->addWidget(DetailsWidget);
Group = new QGroupBox(this);
Group->setObjectName("spk_pg_qsstest_groupbox");
Group->setTitle("GroupBox");
Group->setLayout(VLayTestWidgets);
VLayInput = new QVBoxLayout;
VLayInput->setObjectName("spk_pg_qsstest_inputlay");
VLayInput->addWidget(TextStylesheet);
VLayInput->addLayout(HLayInputBtns);
VLayWidgets = new QVBoxLayout;
VLayWidgets->setObjectName("spk_pg_qsstest_widgetlay");
VLayWidgets->addWidget(Group);
VLayWidgets->addWidget(SlideH);
VLayWidgets->addWidget(Prog);
HLay4Slider = new QHBoxLayout;
HLay4Slider->setObjectName("spk_pg_qsstest_hlay_for_slider");
HLay4Slider->addLayout(VLayWidgets);
HLay4Slider->addWidget(SlideV);
WidL = new QWidget(this);
WidL->setObjectName("spk_pg_qsstest_widleft");
WidL->setLayout(HLay4Slider);
WidL->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred);
WidR = new QWidget(this);
WidR->setObjectName("spk_pg_qsstest_widright");
WidR->setLayout(VLayInput);
addWidget(WidL);
addWidget(WidR);
}
void SpkUi::SpkPageUiTest::SetStylesheet()
{
qApp->setStyleSheet(TextStylesheet->toPlainText());
}
void SpkUi::SpkPageUiTest::FetchStylesheet()
{
TextStylesheet->setPlainText(SpkUi::CurrentStylesheet);
}
void SpkUi::SpkPageUiTest::ShowPopupSlot()
{
SpkUi::Popup->Show(PopupText->text());
}

View File

@@ -1,361 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SpkHomepage</class>
<widget class="QWidget" name="SpkHomepage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>648</width>
<height>554</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="hlayTitle">
<item>
<widget class="QLabel" name="lblIcon">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>{spark-store-icon}</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblTitle">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<pointsize>40</pointsize>
</font>
</property>
<property name="text">
<string>Spark Store</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="lblAuthor">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Brought to you by &lt;a href=&quot;https://spark-app.store&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;Spark Project&lt;/span&gt;&lt;/a&gt;, an open source software project.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>50</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QGridLayout" name="vlayBtns">
<item row="1" column="1">
<widget class="SpkNotifyDot" name="lblNewAnnouncement">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>0</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblAboutProject">
<property name="text">
<string>About this project...</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="btnFeedback">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Feedback</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QPushButton" name="btnDonation">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Donation</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="btnAnnouncements">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Announcements</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="btnSubmit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Submit Software</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="widReloadCategory" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="lblCategoryErrIcon">
<property name="text">
<string>{error-icon}</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblCategoryErr">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Category failed to load. Click the button to retry.</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnReloadCategory">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Reload</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lblVersion">
<property name="text">
<string>Version %1</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnAbout">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>About</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>SpkNotifyDot</class>
<extends>QLabel</extends>
<header>spknotifydot.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -1,472 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SpkUiSettings</class>
<widget class="QWidget" name="SpkUiSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>581</width>
<height>896</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="layTitle">
<item>
<widget class="QLabel" name="lblSettingsTitle">
<property name="text">
<string>Spark Store Settings</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnSave">
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="lineTitle">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblRestartHint">
<property name="text">
<string>Configuration entries marked &quot;*&quot; will only take effect after restarting Spark Store.</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="laySettings">
<item row="5" column="0">
<widget class="QLabel" name="lblApiUrl">
<property name="text">
<string>Store API URL</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblResourceUrl">
<property name="text">
<string>Store resource URL</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="edtDownloadPath">
<property name="spkcfg_key" stdset="0">
<string notr="true">dirs/download</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblResourceCachePath">
<property name="text">
<string>Resource cache path*</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblAptRepo">
<property name="text">
<string>APT Repository</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLineEdit" name="edtResourceUrl">
<property name="spkcfg_key" stdset="0">
<string>url/res</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="layAptRepo">
<property name="spacing">
<number>4</number>
</property>
<item>
<widget class="QComboBox" name="cmbAptRepo">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="spkcfg_key" stdset="0">
<string notr="true">pkgmgr/apt_repo</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnFetchAptRepo">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Fetch all</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnApplyAptRepo">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Apply</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblLightDarkTheme">
<property name="text">
<string>Light/dark theme</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="edtResourceCachePath">
<property name="spkcfg_key" stdset="0">
<string>dirs/cache</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPlainTextEdit" name="edtDownloadServers">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>80</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>150</height>
</size>
</property>
<property name="baseSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="spkcfg_key" stdset="0">
<string notr="true">download/servers</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cmbLightDarkTheme">
<property name="currentIndex">
<number>3</number>
</property>
<property name="frame">
<bool>true</bool>
</property>
<property name="spkcfg_key" stdset="0">
<string notr="true">gui/theme</string>
</property>
<item>
<property name="text">
<string>Auto (DDE only)</string>
</property>
</item>
<item>
<property name="text">
<string>Always Light</string>
</property>
</item>
<item>
<property name="text">
<string>Always Dark</string>
</property>
</item>
<item>
<property name="text">
<string>Manual</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblDownloadPath">
<property name="toolTip">
<string/>
</property>
<property name="toolTipDuration">
<number>-1</number>
</property>
<property name="text">
<string>Download path*</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblDownloadServers">
<property name="toolTip">
<string>Server addresses are separated with two semicolons (;;).</string>
</property>
<property name="toolTipDuration">
<number>1</number>
</property>
<property name="text">
<string>Download servers</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="edtApiUrl">
<property name="spkcfg_key" stdset="0">
<string>url/api</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="lblRepoListUrl">
<property name="text">
<string>APT Repository Source</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLineEdit" name="edtRepoListUrl"/>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="lblHomeNotice">
<property name="text">
<string>Note: character &quot;*&quot; in paths are replaced with the current user's home path.</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblCleanup">
<property name="text">
<string>Cache and Downloads cleanup</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblCleanupDescription">
<property name="text">
<string>Spark Store caches resources such as app icons and screenshots locally. If you want to free up space, you can clear them here or delete them manually.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="layCleanup">
<item row="1" column="3">
<widget class="QPushButton" name="btnCleanDownloadedContent">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="btnViewResourceCache">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>View</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="btnViewDownloadedContent">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>View</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblDownloadedContent">
<property name="text">
<string>Downloaded content</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblResourceCache">
<property name="text">
<string>Resource cache</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QPushButton" name="btnCleanResourceCache">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblSizeResourceCache">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblSizeDownloadedContent">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="lblAdvanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblAdvancedDescription">
<property name="text">
<string>Advanced settings are low-level configurations that can affect usability and are not meant to be modified by average users.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="layAdvanced">
<item row="0" column="0">
<widget class="QLabel" name="lblConcurrentResDownloads">
<property name="text">
<string>Concurrent resource downloads*</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="spnConcurrentResDownloads">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>6</number>
</property>
<property name="value">
<number>5</number>
</property>
<property name="spkcfg_key" stdset="0">
<string>resource/concurrent</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblQssPath">
<property name="text">
<string>Default Qt Style Sheet template*</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="edtQssPath">
<property name="spkcfg_key" stdset="0">
<string>internal/qss_path</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,133 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * 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.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** 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
** OWNER 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."
**
** $QT_END_LICENSE$
**
****************************************************************************/
/*
* Slight modifications has been done to the code to make it fit into the project.
*/
#include "qt/elidedlabel.h"
#include <QPainter>
#include <QSizePolicy>
#include <QTextLayout>
//! [0]
ElidedLabel::ElidedLabel(const QString &text, QWidget *parent)
: QFrame(parent)
, elided(false)
, content(text)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
}
//! [0]
//! [1]
void ElidedLabel::setText(const QString &newText)
{
content = newText;
update();
}
//! [1]
//! [2]
void ElidedLabel::paintEvent(QPaintEvent *event)
{
QFrame::paintEvent(event);
QPainter painter(this);
QFontMetrics fontMetrics = painter.fontMetrics();
bool didElide = false;
int lineSpacing = fontMetrics.lineSpacing();
int y = 0;
QTextLayout textLayout(content, painter.font());
textLayout.beginLayout();
forever {
QTextLine line = textLayout.createLine();
if (!line.isValid())
break;
line.setLineWidth(width());
int nextLineY = y + lineSpacing;
if (height() >= nextLineY + lineSpacing) {
line.draw(&painter, QPoint(0, y));
y = nextLineY;
//! [2]
//! [3]
} else {
QString lastLine = content.mid(line.textStart());
QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, width());
painter.drawText(QPoint(0, y + fontMetrics.ascent()), elidedLastLine);
line = textLayout.createLine();
didElide = line.isValid();
break;
}
}
textLayout.endLayout();
//! [3]
//! [4]
if (didElide != elided) {
elided = didElide;
emit elisionChanged(didElide);
}
}
ElidedLabel::ElidedLabel(QWidget *parent)
: QFrame(parent)
, elided(false)
, content("")
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
}
//! [4]

View File

@@ -1,73 +0,0 @@
#include <QDesktopServices>
#include "spkabout.h"
#include "gitver.h"
SpkAbout::SpkAbout(QWidget *parent) : SpkDialog(parent)
{
setWindowModality(Qt::ApplicationModal);
// mDialogWidget->setMaximumWidth(600);
mDialogWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setFixedSize(550, 450);
SetResizable(false); // Do you like the dilemma of using self created widget?
mIconLay = new QHBoxLayout;
mSpkVersion = new QLabel;
mSpkVersion->setText(tr("<h1>Spark Store</h1>"
"<h3>Version <a href=\"https://www.spark-app.store\">%1</a></h3>"
"<t>Built on %2 %3</t>")
.arg(GitVer::DescribeTags(),
__DATE__, __TIME__));
connect(mSpkVersion, &QLabel::linkActivated,
[](const QString &link){ QDesktopServices::openUrl(link); });
mSpkIcon = new QLabel;
mSpkIcon->setPixmap(QIcon(":/icons/spark-store.svg").pixmap(QSize(128, 128)));
auto description = tr(
"Spark Store was started when Chinese home-grown Linux operating systems "
"had initially hit the market. Because the Linux desktop ecosystem is not "
"good enough at the time being, volunteers built this small App Store in "
"the hope that users can get useful applications faster.\n\n"
"Right now we are not just a Chinese group. We are discovering our way into "
"more Debian-based Linux OSes, and build a real community software repository "
"for users around the world.");
mDescriptionText = new QLabel;
mDescriptionText->setObjectName("spk_about_desc");
mDescriptionText->setWordWrap(true);
mDescriptionText->setText(description);
mIconLay->addStretch(3);
mIconLay->addWidget(mSpkIcon);
mIconLay->addStretch(1);
mIconLay->addWidget(mSpkVersion);
mIconLay->addStretch(3);
mIconLay->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
AddStretch();
AddLayout(mIconLay);
AddSpacing(18);
AddWidget(mDescriptionText);
AddStretch();
SetMargin(18, 0, 18, 18);
GetTitleBar()->SetOperationButton(SpkTitleBar::OperationButton::Close);
GetTitleBar()->SetTitle(tr("About Spark Store"));
}
SpkAbout::~SpkAbout()
{
// delete mIconLay;
// delete mDescriptionText;
}
void SpkAbout::Show()
{
SpkAbout *b = new SpkAbout;
b->Exec();
delete b;
}

View File

@@ -1,63 +0,0 @@
#include <QPainter>
#include <QStyleOption>
#include "spkappitem.h"
#include "qt/elidedlabel.h"
const QSize SpkAppItem::IconSize_;
SpkAppItem::SpkAppItem(int appId, QWidget *parent) : QWidget(parent)
{
mAppId = appId;
mMainLay = new QHBoxLayout(this);
mLayText = new QVBoxLayout;
mIcon = new QLabel;
mIcon->setFixedSize(IconSize, IconSize);
mIcon->setAutoFillBackground(false);
// NOTE: Make mTitle ElidedTitle too?
mTitle = new QLabel;
mTitle->setWordWrap(false);
mTitle->setObjectName("styAppItmTitle");
mTitle->setAutoFillBackground(true);
mDescription = new ElidedLabel;
// mDescription->setWordWrap(true); // Commented out since ElidedLabel lacks of these methods
mDescription->setObjectName("styAppItmDesc");
mDescription->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
// mDescription->setAlignment(Qt::AlignTop | Qt::AlignLeft);
// mDescription->setAutoFillBackground(true);
mLayText->addWidget(mTitle);
mLayText->addWidget(mDescription);
mLayText->setAlignment(Qt::AlignTop);
mMainLay->setMargin(5);
mMainLay->addWidget(mIcon);
mMainLay->addLayout(mLayText);
setMinimumHeight(82);
setMaximumHeight(82);
setMinimumWidth(300);
}
void SpkAppItem::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e)
QStyleOption opt;
opt.init(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}
void SpkAppItem::mousePressEvent(QMouseEvent *e)
{
mPressCond = true;
}
void SpkAppItem::mouseReleaseEvent(QMouseEvent *e)
{
if(mPressCond)
emit clicked(mAppId);
mPressCond = false;
}

View File

@@ -1,61 +0,0 @@
#include "spkmainwindow.h"
namespace SpkUi
{
SpkCategorySelector::SpkCategorySelector(QWidget *parent) : QWidget(parent)
{
mBtnLayout = new QVBoxLayout(this);
mGroup = new QButtonGroup(this);
}
void SpkCategorySelector::AddButton(QString aBtnText, int aCategoryId, QPixmap *aBtnIcon)
{
auto btn = new SpkCategoryButton(this);
btn->SetText(aBtnText);
if(aBtnIcon)
btn->SetIcon(*aBtnIcon);
mBtnList.append(btn);
mGroup->addButton(btn, aCategoryId ? aCategoryId : -1);
mBtnLayout->addWidget(btn);
}
void SpkCategorySelector::DeleteAllButtons() // TODO: UNTESTED
{
foreach (auto i, mBtnList)
{
mBtnLayout->removeWidget(i);
mGroup->removeButton(i);
i->deleteLater();
}
mBtnList.clear();
}
SpkCategoryButton::SpkCategoryButton(QWidget *parent) : QPushButton(parent)
{
mIcon = new QLabel(this);
mIcon->setObjectName("spk_categorybtn_label");
mText = new QLabel(this);
mText->setObjectName("spk_categorybtn_text");
mLayout = new QHBoxLayout;
mLayout->setObjectName("spk_categorybtn_lay");
mLayout->addSpacing(Spacing);
mLayout->addWidget(mIcon);
mLayout->addSpacing(Spacing);
mLayout->addStretch();
mLayout->addWidget(mText);
mLayout->addStretch();
mLayout->addSpacing(Spacing);
setLayout(mLayout);
}
void SpkCategoryButton::SetIcon(QPixmap aImage)
{
mIcon->setPixmap(aImage);
}
void SpkCategoryButton::SetText(QString aText)
{
mText->setText(aText);
}
}

View File

@@ -1,115 +0,0 @@
#include "spkdialog.h"
#include <QEventLoop>
SpkDialog::SpkDialog(QWidget *parent) : SpkWindow(parent)
{
mDialogWidget = new QWidget;
mMainVLay = new QVBoxLayout;
mWidgetsVLay = new QVBoxLayout();
mBtnLay = new QHBoxLayout();
mBtnGroup = new QButtonGroup(this);
mMainVLay->addLayout(mWidgetsVLay);
mMainVLay->addLayout(mBtnLay);
mBtnLay->setAlignment(Qt::AlignCenter);
SetCentralWidget(mDialogWidget);
mDialogWidget->setLayout(mMainVLay);
// idClicked is not available on platforms we support, shouldn't change it
connect(mBtnGroup, QOverload<int>::of(&QButtonGroup::buttonClicked),
this, &SpkDialog::ButtonPressed);
connect(this, &SpkWindow::Closed, this, &SpkDialog::ForceClose);
}
SpkDialog::~SpkDialog()
{
auto itp = mParentsList.begin();
for(auto itw = mWidgetsList.begin(); itw != mWidgetsList.end(); itw++)
{
(*itw)->setParent(*(itp++));// We shall never take the ownership of these widgets
}
delete mDialogWidget;
}
void SpkDialog::AddButton(QString text, SpkUi::SpkButtonStyle style)
{
auto b = new QPushButton();
b->setText(text);
b->setMinimumWidth(100);
b->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
switch(style)
{
case SpkUi::SpkButtonStyle::Recommend:
b->setObjectName("sty_recommendbtn");
break;
case SpkUi::SpkButtonStyle::Warn:
b->setObjectName("sty_warnbtn");
break;
default:
break;
}
mBtnLay->addWidget(b);
mBtnGroup->addButton(b);
}
void SpkDialog::AddWidget(QWidget *w)
{
// Adding a widget does not take the ownership.
mWidgetsVLay->addWidget(w);
mWidgetsList << w;
mParentsList << w->parentWidget();
}
void SpkDialog::AddLayout(QLayout *w)
{
mWidgetsVLay->addLayout(w);
mWidgetsList << w;
mParentsList << w->parentWidget();
}
void SpkDialog::AddSpacing(int a)
{
mWidgetsVLay->addSpacing(a);
}
void SpkDialog::AddStretch(int a)
{
mWidgetsVLay->addStretch(a);
}
void SpkDialog::SetMargin(int a)
{
mWidgetsVLay->setMargin(a);
}
int SpkDialog::Exec()
{
QEventLoop loop;
connect(this, &SpkDialog::ExitEventLoop, &loop, &QEventLoop::exit);
connect(this, &SpkDialog::CloseWindow, this, &QMainWindow::close);
show();
return loop.exec();
}
void SpkDialog::ButtonPressed(int aBtnId)
{
disconnect(this, &SpkWindow::Closed, this, &SpkDialog::ForceClose);
emit ExitEventLoop(-aBtnId - 2);
emit CloseWindow();
}
void SpkDialog::ForceClose()
{
disconnect(this, &SpkDialog::CloseWindow, this, &QMainWindow::close);
emit ExitEventLoop(-1);
}
void SpkDialog::SetMargin(int left, int top, int right, int bottom)
{
mWidgetsVLay->setContentsMargins(left, top, right, bottom);
}

View File

@@ -1,201 +0,0 @@

#include "spkdownloadentry.h"
#include "spklogging.h"
#include "spkutils.h"
#include <QDebug>
constexpr QSize SpkDownloadEntry::IconSize;
SpkDownloadEntry::SpkDownloadEntry(QWidget *parent)
{
mIcon = new QLabel;
mAppName = new ElidedLabel;
mMessage = new QLabel;
mProgress = new QProgressBar;
mLoading = new SpkLoading;
mBtnDelete = new QPushButton;
mBtnActions = new QPushButton;
mLayInfo = new QVBoxLayout;
mLayMsgs = new QHBoxLayout;
mLayMain = new QHBoxLayout;
mLoading->setVisible(false);
mIcon->setFixedSize(IconSize);
mProgress->setRange(0, 1000);
mLayMsgs->addWidget(mAppName);
mLayMsgs->addStretch();
mLayMsgs->addWidget(mMessage);
mLayInfo->addLayout(mLayMsgs);
mLayInfo->addWidget(mProgress);
mLayInfo->setAlignment(Qt::AlignVCenter);
mLayMain->addWidget(mIcon);
mLayMain->addLayout(mLayInfo);
mLayMain->addWidget(mLoading);
mLayMain->addWidget(mBtnActions);
mLayMain->addWidget(mBtnDelete);
setLayout(mLayMain);
connect(mBtnActions, &QPushButton::clicked, this, &SpkDownloadEntry::ActionButton);
connect(mBtnDelete, &QPushButton::clicked, this, &SpkDownloadEntry::DeleteButton);
mStatus = Invalid;
mLastReportTime = QTime::currentTime();
}
SpkDownloadEntry::~SpkDownloadEntry()
{
// TODO
}
void SpkDownloadEntry::SetTotalBytes(qint64 total)
{
mTotalBytes = total;
mReadableTotalSize = SpkUtils::BytesToSize(total);
mLastReportTime = QTime::currentTime();
}
void SpkDownloadEntry::SetBasicInfo(QString name, QPixmap icon, QString filePath)
{
mAppName->setText(name);
mIcon->setPixmap(icon.scaled(IconSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
mFilePath = filePath;
}
void SpkDownloadEntry::SetStatus(DownloadEntryStatus status, QString msg)
{
mStatus = status;
switch(status)
{
case Waiting:
mMessage->setText(tr("Waiting for download"));
mProgress->setVisible(false);
mBtnActions->setVisible(false);
mBtnDelete->setVisible(true);
mBtnDelete->setText(tr("Cancel"));
break;
case Starting:
mMessage->setText(tr("Starting download"));
mBtnDelete->setVisible(false);
break;
case Downloading:
mMessage->setText(tr(""));
mProgress->setVisible(true);
mBtnActions->setVisible(false);
mBtnDelete->setVisible(true);
break;
case DownloadFailed:
mMessage->setText(msg);
mProgress->setVisible(false);
mBtnActions->setVisible(true);
mBtnActions->setText(tr("Retry"));
break;
case ToBeInstalled:
mMessage->setText(tr("Download Finished"));
mProgress->setVisible(false);
mBtnActions->setVisible(true);
mBtnDelete->setVisible(false);
mBtnActions->setText(tr("Install"));
break;
case Installing:
mMessage->setText("");
mProgress->setVisible(false);
mBtnActions->setVisible(false);
mBtnDelete->setVisible(false);
mLoading->setVisible(true);
mLoading->Begin();
break;
case Installed:
mMessage->setText(tr("Installed"));
mLoading->End();
mLoading->setVisible(false);
mBtnDelete->setVisible(true);
mBtnDelete->setText(tr("Delete"));
break;
case InstallFailed:
mMessage->setText(msg.isEmpty() ? tr("Install Failed") : msg);
mLoading->End();
mLoading->setVisible(false);
mBtnActions->setVisible(true);
mBtnActions->setText(tr("Install"));
mBtnDelete->setVisible(true);
mBtnDelete->setText(tr("Cancel"));
break;
case Invalid:
break;
}
}
void SpkDownloadEntry::Progress(qint64 bytes)
{
auto now = QTime::currentTime();
auto msecDiff = mLastReportTime.msecsTo(now);
if(msecDiff != 0)
{
auto bytesPerSec = (bytes - mDownloadedBytes) / (msecDiff / 1000.0);
qDebug() << "Bytes" << bytes - mDownloadedBytes
<< "MsDiff" << msecDiff / 1000.0
<< "Bytes-Per-Seg" << bytesPerSec;
auto speedSize = SpkUtils::BytesToSize(static_cast<size_t>(bytesPerSec));
mMessage->setText(QString("%1/%2(%3/s)")
.arg(SpkUtils::BytesToSize(bytes), mReadableTotalSize, speedSize));
}
mDownloadedBytes = bytes;
mProgress->setValue(static_cast<int>(((double)bytes) / mTotalBytes * 1000));
mLastReportTime = now;
}
void SpkDownloadEntry::ActionButton()
{
switch(mStatus)
{
case DownloadFailed:
emit Action(RetryDownload);
break;
case ToBeInstalled:
case InstallFailed:
emit Action(StartInstall);
break;
default:
break;
}
}
void SpkDownloadEntry::DeleteButton()
{
switch(mStatus)
{
case Waiting:
case DownloadFailed:
case Installed:
case InstallFailed:
case ToBeInstalled:
emit Action(RemoveEntry);
break;
case Downloading:
emit Action(AbortDownload);
break;
default:
break;
}
}

View File

@@ -1,56 +0,0 @@
#include <QMargins>
#include <QPainter>
#include <QVariant>
#include <QDebug>
#include "spkiconbutton.h"
SpkIconButton::SpkIconButton(QWidget *parent) :
QPushButton(parent)
{
setFocusPolicy(Qt::NoFocus);
}
void SpkIconButton::SetIcon(QIcon i, QSize s)
{
mPmapPaintedIcon = i.pixmap(s);
setFixedSize((mPmapSize = s.grownBy(QMargins(IconMargin, IconMargin, IconMargin, IconMargin))));
}
void SpkIconButton::SetIcon(QPixmap m)
{
mPmapPaintedIcon = m;
setFixedSize((mPmapSize = m.size().grownBy(QMargins(IconMargin, IconMargin,
IconMargin, IconMargin))));
}
void SpkIconButton::SetIconSize(QSize s)
{
setFixedSize((mPmapSize = s.grownBy(QMargins(IconMargin, IconMargin, IconMargin, IconMargin))));
}
void SpkIconButton::paintEvent(QPaintEvent *e)
{
QPushButton::paintEvent(e);
// Paint the icon mask
QPainter p(this), p1(&mPmapPaintedIcon);
QBrush b(Qt::SolidPattern);
p.drawPixmap(IconMargin, IconMargin, mPmapPaintedIcon);
if(isDown() || isChecked())
{
b.setColor(SpkUi::ColorBtnMaskSelected);
}
else
{
b.setColor(SpkUi::ColorBtnMaskUnselected);
}
p1.setCompositionMode(QPainter::CompositionMode_SourceIn);
p1.fillRect(0, 0, mPmapSize.width(), mPmapSize.height(), b);
p1.end();
p.drawPixmap(IconMargin, IconMargin, mPmapPaintedIcon);
p.end();
}

View File

@@ -1,120 +0,0 @@
#include "spktitlebar.h"
#include "spkimgviewer.h"
#include "spkui_general.h"
#include <QDebug>
#include <QFocusEvent>
#include <QGuiApplication>
#include <QScreen>
SpkImgViewer::SpkImgViewer(QWidget *parent) :
SpkWindow(parent),
mIconLoading(QIcon(":/icons/loading-icon.svg").pixmap({ 72, 72 }))
{
mImgIndict = new QLabel;
mImgIndict->setText("%1/%2");
mBtnPrev = new QPushButton;
mBtnPrev->setText("<");
mBtnNext = new QPushButton;
mBtnNext->setText(">");
auto titleBar = GetTitleBar();
titleBar->SetUseIcon(false);
titleBar->SetTitle(tr("Image Preview"));
titleBar->SetOperationButton(SpkTitleBar::OperationButton::Close);
auto lay = titleBar->GetUserSpace();
lay->setAlignment(Qt::AlignVCenter);
lay->addStretch();
lay->addWidget(mBtnPrev);
lay->addWidget(mImgIndict);
lay->addWidget(mBtnNext);
lay->addStretch();
mImgArea = new QScrollArea;
mImgArea->setWidgetResizable(true);
mImgArea->setContentsMargins(10, 10, 10, 10);
mImgShow = new ImgView;
mImgArea->setWidget(mImgShow);
auto w = new QWidget;
auto l = new QHBoxLayout;
l->setContentsMargins(10, 10, 10, 10);
l->addWidget(mImgArea);
w->setLayout(l);
SetCentralWidget(w);
connect(mBtnPrev, &QPushButton::clicked,
[&](){ if(mCurrentImg > 0) { SwitchToImage(--mCurrentImg); } });
connect(mBtnNext, &QPushButton::clicked,
[&](){ if(mCurrentImg < mTotalImg) { SwitchToImage(++mCurrentImg); } });
}
void SpkImgViewer::ShowWithImage(int idx)
{
SwitchToImage(idx);
show();
}
void SpkImgViewer::Clear()
{
mImgMap.clear();
mImgShow->SetPixmap(nullptr);
mCurrentImg = 1;
}
void SpkImgViewer::SetPixmap(int idx, QPixmap *img)
{
mImgMap[idx] = img;
if(mCurrentImg == idx)
{
mImgShow->SetPixmap(img);
}
ResizeToFitImageSize(img->size());
}
void SpkImgViewer::SwitchToImage(int idx)
{
auto img = mImgMap.value(idx, nullptr);
mCurrentImg = idx;
mImgShow->SetPixmap(img ? img : &mIconLoading);
if(img)
ResizeToFitImageSize(img->size());
if(idx == 1)
{
mBtnPrev->setEnabled(false);
mBtnNext->setEnabled(true);
}
else if(idx == mTotalImg)
{
mBtnPrev->setEnabled(true);
mBtnNext->setEnabled(false);
}
else
{
mBtnPrev->setEnabled(true);
mBtnNext->setEnabled(true);
}
mImgIndict->setText(QString("%1/%2").arg(mCurrentImg).arg(mTotalImg));
}
bool SpkImgViewer::event(QEvent *e)
{
if(e->type() == QEvent::WindowDeactivate)
close();
return SpkWindow::event(e);
}
void SpkImgViewer::ResizeToFitImageSize(QSize s)
{
auto targetSize = s;
targetSize.rheight() += SpkTitleBar::Height;
targetSize = s.grownBy(QMargins(10, 10, 10, 10));
targetSize = targetSize.boundedTo(SpkUi::PrimaryScreenSize * 0.8);
resize(targetSize);
targetSize /= 2;
auto targetPos = SpkUi::PrimaryScreenSize / 2 - targetSize;
move(targetPos.width(), targetPos.height());
}

View File

@@ -1,79 +0,0 @@
#include <QPaintEvent>
#include <QPainter>
#include "spkloading.h"
#include "spkui_general.h"
SpkLoading::SpkLoading(QWidget *parent) : QFrame(parent)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
mAnimTimer = new QTimeLine(400, this);
mAnimTimer->setFrameRange(10, 30);
mAnimTimer->setEasingCurve(QEasingCurve::InCubic);
for(int i = 0; i < 5; i++)
mSizeList.append(20);
connect(mAnimTimer, &QTimeLine::frameChanged, this, &SpkLoading::timer);
connect(mAnimTimer, &QTimeLine::finished, this, &SpkLoading::loop);
}
void SpkLoading::paintEvent(QPaintEvent *e)
{
QPainter p(this);
QPen pen(Qt::NoPen);
QBrush b(SpkUi::CurrentColorSet[SpkUi::Qss::AccentColor], Qt::SolidPattern);
p.setBrush(b);
p.setPen(pen);
p.setRenderHint(QPainter::Antialiasing);
dx = width() / 2 - dh * 2;
dy = height() / 2;
double r;
for(int i = 0; i < 5; i++)
{
r = dh * mSizeList[i] / 80;
p.drawEllipse({ dx, dy }, r, r);
dx += dh;
}
e->accept();
}
void SpkLoading::resizeEvent(QResizeEvent *e)
{
// Calculate size of drawing space
if(mUserHeight != 0 && mUserHeight * 5 <= e->size().width())
{
dw = 5 * mUserHeight;
dh = mUserHeight;
return;
}
dh = e->size().height();
if(width() < dh * 5)
{
dw = e->size().width();
dh = dw / 5;
}
else
dw = dh * 5;
}
void SpkLoading::timer(int s)
{
for(int i = 4; i > 0; i--)
mSizeList[i] = mSizeList[i - 1];
mSizeList[0] = s;
update();
}
void SpkLoading::loop()
{
mAnimTimer->setDirection(mAnimTimer->direction() == QTimeLine::Forward ?
QTimeLine::Backward : QTimeLine::Forward);
mAnimTimer->start();
}
void SpkLoading::reset()
{
for(int i = 0; i < 5; i++)
mSizeList[i] = 20;
update();
}

View File

@@ -1,570 +0,0 @@
#include <QGuiApplication>
#include <QScreen>
#include <QJsonArray>
#include "spkmsgbox.h"
#include "spkmainwindow.h"
#include "spklogging.h"
#include "spkutils.h"
#include "spkuimsg.h"
SpkMainWindow::SpkMainWindow(QWidget *parent) : SpkWindow(parent)
{
ui = new SpkUi::SpkMainWidget(this);
Initialize();
SetCentralWidget(ui);
RefreshCategoryData();
GetTitleBar()->SetTitle("");
GetTitleBar()->SetUseIcon(true);
GetTitleBar()->SetIcon(QIcon(":/icons/spark-store.svg").pixmap({ 40, 40 }));
GetTitleBar()->setObjectName("spk_mw_titlebar");
GetTitleBar()->setAttribute(Qt::WA_StyledBackground);
auto size = QGuiApplication::primaryScreen()->size() * 0.5;
size = size.expandedTo(QSize(900, 600));
resize(size);
auto pos = QGuiApplication::primaryScreen()->size() * 0.5 - size * 0.5;
move(pos.width(), pos.height());
}
void SpkMainWindow::SwitchDayNightTheme()
{
if(SpkUi::CurrentStyle == SpkUi::Dark)
SpkUi::SetGlobalStyle(SpkUi::Light, true);
else
SpkUi::SetGlobalStyle(SpkUi::Dark, true);
ReloadThemedUiIcons();
}
void SpkMainWindow::SwitchToPage(SpkUi::SpkStackedPages page)
{
if(mCurrentPage != page)
{
ui->Pager->setCurrentIndex(int(page));
mCurrentPage = page;
// If the page is a SpkPageBase (with a resource context), activate it for resource acquisition
auto tryActivate = qobject_cast<SpkPageBase *>(ui->Pager->currentWidget());
if(tryActivate)
tryActivate->Activated();
ui->BtnBack->setVisible(page == SpkUi::SpkStackedPages::PgAppDetails);
ui->BtnBack->setEnabled(true);
}
}
void SpkMainWindow::PopulateCategories(QJsonArray aCategoryData)
{
using SpkUi::SpkSidebarSelector;
QTreeWidgetItem *catg;
if(ui->CategoryParentItem->childCount()) // Clear all existing children if there is any
foreach(auto &i, ui->CategoryParentItem->takeChildren())
delete i;
foreach(auto i, aCategoryData)
{
if(i.isObject())
{
auto j = i.toObject();
double typeId;
QString typeName;
if(j.contains("type_id") && j.value("type_id").isDouble())
typeId = j.value("type_id").toDouble();
else goto WRONG_CATEGORY;
if(j.contains("type_name") && j.value("type_name").isString())
typeName = j.value("type_name").toString();
else goto WRONG_CATEGORY;
catg = new QTreeWidgetItem(ui->CategoryParentItem, QStringList(typeName));
catg->setData(0, SpkSidebarSelector::RoleItemIsCategory, true);
catg->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, typeId);
continue;
WRONG_CATEGORY:;
}
ui->CategoryParentItem->setExpanded(true);
}
}
void SpkMainWindow::RefreshCategoryData()
{
// Asynchronously call category API
using namespace SpkUtils;
VerifySingleRequest(mCategoryGetReply);
mCategoryGetReply = STORE->SendApiRequest("type/get_type_list");
DeleteReplyLater(mCategoryGetReply);
connect(mCategoryGetReply, &QNetworkReply::finished, this, &SpkMainWindow::CategoryDataReceived);
}
void SpkMainWindow::CategoryDataReceived()
{
QJsonValue retval;
auto verify = SpkUtils::VerifyReplyJson(mCategoryGetReply, retval);
if(verify || !retval.isArray())
{
sErr(tr("Failed to load categories! Type=%1 Code=%2").arg(retval.type()).arg(verify));
sNotify(tr("Cannot load categories! Type: %1 Code: %2").arg(retval.type()).arg(verify));
ui->PageHome->ui->widReloadCategory->setVisible(true);
return;
}
ui->PageHome->ui->widReloadCategory->setVisible(false);
PopulateCategories(retval.toArray());
}
void SpkMainWindow::EnterCategoryList(int aCategoryId, int aPage)
{
// Asynchronously call category API
using namespace SpkUtils;
VerifySingleRequest(mCategoryAppListGetReply);
QJsonObject reqData;
QJsonDocument reqDoc;
reqData.insert("type_id", QJsonValue(aCategoryId));
reqData.insert("page", QJsonValue(aPage));
reqDoc.setObject(reqData);
mCategoryAppListGetReply = STORE->SendApiRequest("application/get_application_list", reqDoc);
DeleteReplyLater(mCategoryAppListGetReply);
connect(mCategoryAppListGetReply, &QNetworkReply::finished,
this, &SpkMainWindow::CategoryListDataReceived);
setCursor(Qt::BusyCursor);
ui->PageAppList->SetCurrentCategory(aCategoryId); // AppList needs to remember current category
}
void SpkMainWindow::CategoryListDataReceived()
{
QJsonValue retval;
setCursor(Qt::ArrowCursor);
int verify = SpkUtils::VerifyReplyJson(mCategoryAppListGetReply, retval);
if(verify || !retval.isObject())
{
sErr(tr("Failed to load app list of category! Type=%1 Code=%2").arg(retval.type()).arg(verify));
sNotify(tr("Failed to load app list of category! Type: %1 Code: %2").arg(retval.type()).arg(verify));
return;
}
SwitchToPage(SpkUi::PgAppList);
PopulateAppList(retval.toObject(), "");
}
void SpkMainWindow::SearchKeyword(QString aKeyword, int aPage)
{
using namespace SpkUtils;
VerifySingleRequest(mCategoryAppListGetReply);
QJsonObject reqData;
QJsonDocument reqDoc;
reqData.insert("application_name", QJsonValue(aKeyword));
reqData.insert("page", QJsonValue(aPage));
reqDoc.setObject(reqData);
mCategoryAppListGetReply = STORE->SendApiRequest("application/get_application_list", reqDoc);
mCategoryAppListGetReply->setProperty("keyword", aKeyword);
DeleteReplyLater(mCategoryAppListGetReply);
connect(mCategoryAppListGetReply, &QNetworkReply::finished,
this, &SpkMainWindow::SearchDataReceived);
setCursor(Qt::BusyCursor);
}
void SpkMainWindow::SearchDataReceived()
{
QJsonValue retval;
setCursor(Qt::ArrowCursor);
auto verify = SpkUtils::VerifyReplyJson(mCategoryAppListGetReply, retval);
if(verify || !retval.isObject())
{
sErr(tr("Failed to search keyword! Type=%1 Code=%2").arg(retval.type()).arg(verify));
sNotify(tr("Failed to search keyword! Type: %1 Code: %2").arg(retval.type()).arg(verify));
return;
}
SwitchToPage(SpkUi::PgAppList);
PopulateAppList(retval.toObject(), mCategoryAppListGetReply->property("keyword").toString());
}
void SpkMainWindow::PopulateAppList(QJsonObject appData, QString &&keyword)
{
auto w = ui->PageAppList;
w->ClearAll();
static auto err =
[](){
sErr("Received invalid application list data!");
SpkUiMessage::SendStoreNotification(tr("Received an invalid response. Please try again!"));
return;
};
int pgCurrent, pgTotal, totalApps;
if(appData.contains("currentPage") && appData.value("currentPage").isDouble())
pgCurrent = appData.value("currentPage").toInt();
else return err();
if(appData.contains("totalPages") && appData.value("totalPages").isDouble())
pgTotal = appData.value("totalPages").toInt();
else return err();
if(appData.contains("count") && appData.value("count").isDouble())
totalApps = appData.value("count").toInt();
else return err();
w->SetPageStatus(pgTotal, pgCurrent, totalApps, keyword);
if(!appData.contains("data") || !appData.value("data").isArray())
return err();
auto apps = appData.value("data").toArray();
for(auto &&i : apps)
{
if(i.isObject())
{
auto j = i.toObject();
QString pkgName, displayName, description, iconPath;
int appid;
if(j.contains("package") && j.value("package").isString())
pkgName = j.value("package").toString();
else continue;
if(j.contains("application_name_zh") && j.value("application_name_zh").isString())
displayName = j.value("application_name_zh").toString();
else continue;
if(j.contains("description") && j.value("description").isString())
description = j.value("description").toString();
else continue;
if(j.contains("application_id") && j.value("application_id").isDouble())
appid = j.value("application_id").toInt();
else continue;
if(j.contains("icons") && j.value("icons").isString())
iconPath = j.value("icons").toString();
else continue;
w->AddApplicationEntry(displayName, pkgName, description, iconPath, appid);
}
}
}
void SpkMainWindow::EnterAppDetails(int aAppId)
{
using namespace SpkUtils;
VerifySingleRequest(mAppDetailsGetReply);
QJsonObject reqData;
QJsonDocument reqDoc;
reqData.insert("application_id", QJsonValue(aAppId));
reqDoc.setObject(reqData);
mAppDetailsGetReply = STORE->SendApiRequest("application/get_application_detail", reqDoc);
DeleteReplyLater(mAppDetailsGetReply);
connect(mAppDetailsGetReply, &QNetworkReply::finished,
this, &SpkMainWindow::AppDetailsDataReceived);
setCursor(Qt::BusyCursor);
}
void SpkMainWindow::AppDetailsDataReceived()
{
QJsonValue retval;
setCursor(Qt::ArrowCursor);
auto verify = SpkUtils::VerifyReplyJson(mAppDetailsGetReply, retval);
if(verify || !retval.isObject())
{
sErr(tr("Failed to open app details page! Type=%1 Code=%2").arg(retval.type()).arg(verify));
sNotify(tr("Failed to open app details page! Type: %1 Code: %2").arg(retval.type()).arg(verify));
return;
}
SwitchToPage(SpkUi::PgAppList);
PopulateAppDetails(retval.toObject());
}
void SpkMainWindow::PopulateAppDetails(QJsonObject appDetails)
{
QString pkgName, author, contributor, site, iconPath, arch, version, details, shortDesc, name,
pkgPath;
QStringList screenshots, tags;
int packageSize;
static auto err =
[](){
sErr("Received invalid application details!");
SpkUiMessage::SendStoreNotification(tr("Received an invalid response. Please try again!"));
return;
};
if(appDetails.contains("package") && appDetails.value("package").isString())
pkgName = appDetails.value("package").toString();
else return err();
if(appDetails.contains("application_name_zh") && appDetails.value("application_name_zh").isString())
name = appDetails.value("application_name_zh").toString();
else name = pkgName;
if(appDetails.contains("version") && appDetails.value("version").isString())
version = appDetails.value("version").toString();
else return err();
if(appDetails.contains("icons") && appDetails.value("icons").isString())
iconPath= appDetails.value("icons").toString();
if(appDetails.contains("author") && appDetails.value("author").isString())
author = appDetails.value("author").toString();
if(appDetails.contains("contributor") && appDetails.value("contributor").isString())
contributor = appDetails.value("contributor").toString();
if(appDetails.contains("website") && appDetails.value("website").isString())
site = appDetails.value("website").toString();
if(appDetails.contains("description") && appDetails.value("description").isString())
shortDesc = appDetails.value("description").toString();
if(appDetails.contains("more") && appDetails.value("more").isString())
details = appDetails.value("more").toString();
if(appDetails.contains("arch") && appDetails.value("arch").isString())
arch = appDetails.value("arch").toString();
if(appDetails.contains("size") && appDetails.value("size").isDouble())
packageSize = appDetails.value("size").toInt();
if(appDetails.contains("deb_url") && appDetails.value("deb_url").isString())
pkgPath = appDetails.value("deb_url").toString();
QJsonArray imgs;
if(appDetails.contains("img_urls") && appDetails.value("img_urls").isArray())
imgs = appDetails.value("img_urls").toArray();
if(!imgs.isEmpty())
for(auto &&i : imgs)
if(i.isString()) screenshots << i.toString();
QJsonArray tags_j;
if(appDetails.contains("tags") && appDetails.value("tags").isArray())
imgs = appDetails.value("tags").toArray();
if(!tags_j.isEmpty())
for(auto &&i : tags_j)
if(i.isString()) tags << i.toString();
// Details string has a strangely appended LF. IDK but still should remove it.
shortDesc = shortDesc.trimmed();
auto w = ui->PageAppDetails;
w->mPkgName->setText(pkgName);
w->mAppTitle->setText(name);
w->mAppShortDesc->setText(shortDesc);
w->mAppDescription->setText(details);
w->mAuthor->SetValue(author);
w->mContributor->SetValue(contributor);
// w->mSite->SetValue(site); // Doesn't look good, I disabled it temporarily. Better solution?
w->SetWebsiteLink(site);
w->mArch->SetValue(arch);
w->mSize->SetValue(SpkUtils::BytesToSize(packageSize));
w->mVersion->setText(version);
w->SetPackagePath(pkgPath);
SwitchToPage(SpkUi::PgAppDetails);
ui->AppDetailsItem->setHidden(false);
ui->CategoryWidget->setCurrentItem(ui->AppDetailsItem);
w->LoadAppResources(pkgName, iconPath, screenshots, tags);
}
void SpkMainWindow::ReloadThemedUiIcons()
{
for(auto &i : mThemedUiIconReferences)
i.first->SetIcon(SpkUi::GetThemedIcon(i.second), QSize { 20, 20 });
}
// ==================== Main Window Initialization ====================
void SpkMainWindow::Initialize()
{
connect(ui->SidebarMgr, &SpkUi::SpkSidebarSelector::SwitchToPage,
this, &SpkMainWindow::SwitchToPage);
connect(ui->SidebarMgr, &SpkUi::SpkSidebarSelector::SwitchToCategory,
this, &SpkMainWindow::EnterCategoryList);
connect(ui->PageAppList, &SpkUi::SpkPageAppList::SwitchListPage,
this, &SpkMainWindow::EnterCategoryList);
connect(ui->PageAppList, &SpkUi::SpkPageAppList::SwitchSearchPage,
this, &SpkMainWindow::SearchKeyword);
connect(ui->SearchEdit, &QLineEdit::returnPressed,
[=](){ emit SearchKeyword(ui->SearchEdit->text(), 1); });
connect(ui->PageAppList, &SpkUi::SpkPageAppList::ApplicationClicked,
this, &SpkMainWindow::EnterAppDetails);
connect(ui->BtnDayNight, &QPushButton::clicked,
this, &SpkMainWindow::SwitchDayNightTheme);
if(SpkUi::States::IsUsingDtkPlugin)
{
connect(SpkUi::DtkPlugin, &SpkDtkPlugin::DarkLightThemeChanged,
this, &SpkMainWindow::ReloadThemedUiIcons);
}
connect(ui->PageAppDetails, &SpkUi::SpkPageAppDetails::RequestDownload,
ui->PageDownloads, &SpkUi::SpkPageDownloads::AddDownloadTask);
connect(ui->PageHome->ui->btnReloadCategory, &QPushButton::clicked,
this, &SpkMainWindow::RefreshCategoryData);
connect(&SpkUi::SpkUiMetaObject, &SpkUi::UiMetaObject::SetThemeButtonVisible,
[=](bool visible)
{
ui->BtnDayNight->setVisible(visible);
ReloadThemedUiIcons();
});
// Register themed button icons
// mThemedUiIconReferences.append({ ui->BtnSettings, "settings" });
mThemedUiIconReferences.append({ ui->BtnDayNight, "daynight" });
ReloadThemedUiIcons();
}
// ==================== Main Widget Initialization ====================
SpkUi::SpkMainWidget::SpkMainWidget(QWidget *parent) : QFrame(parent)
{
setObjectName("spk_mainwidget");
Pager = new QStackedWidget(this);
Pager->setObjectName("spk_mw_pager");
Pager->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
SidebarMgr = new SpkSidebarSelector(this);
SidebarMgr->setObjectName("spk_mw_sidebar_mgr");
BtnSettings = new SpkIconButton(this);
BtnSettings->setObjectName("styPlainChkBtn");
BtnSettings->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
BtnSettings->setCheckable(true);
BtnSettings->setFixedSize({ 40, 40 });
BtnSettings->SetIcon(QIcon(":/icons/settings.svg"), QSize(20, 20));
BtnSettings->setProperty("spk_pageno", PgSettings);
SidebarMgr->BindPageSwitcherButton(BtnSettings);
BtnDayNight = new SpkIconButton(this);
BtnDayNight->setObjectName("styPlainChkBtn");
BtnDayNight->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
BtnDayNight->setFixedSize({ 40, 40 });
BtnDayNight->SetIcon(QIcon(":/icons/daynight.svg"), QSize(20, 20));
BtnBack = new SpkIconButton(this);
BtnBack->setFixedSize({ 40, 40 });
BtnBack->SetIcon(QIcon(":/icons/back.svg"), QSize(20, 20));
BtnBack->setVisible(false);
using SpkUi::SpkSidebarSelector;
CategoryWidget = new SpkSidebarTree(this);
CategoryWidget->setObjectName("styMwCateg");
CategoryWidget->setAutoFillBackground(true);
CategoryWidget->setColumnCount(1);
CategoryWidget->setHeaderHidden(true);
CategoryWidget->setSelectionMode(QAbstractItemView::SelectionMode::SingleSelection);
CategoryWidget->setFixedWidth(200);
//============ Sidebar entries BEGIN ============
HomepageItem = new QTreeWidgetItem(QStringList(tr("Home")));
HomepageItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
HomepageItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgHomepage);
AppDetailsItem = new QTreeWidgetItem(QStringList(tr("App Details")));
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
AppDetailsItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgAppDetails);
CategoryParentItem = new QTreeWidgetItem(QStringList(tr("Categories")));
CategoryParentItem->setFlags(CategoryParentItem->flags().setFlag(Qt::ItemIsSelectable, false));
DownloadsItem = new QTreeWidgetItem(QStringList(tr("Downloads")));
DownloadsItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
DownloadsItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgDownloads);
#ifndef NDEBUG
UiTestItem = new QTreeWidgetItem(QStringList(tr("UI TEST")));
UiTestItem->setData(0, SpkSidebarSelector::RoleItemIsCategory, false);
UiTestItem->setData(0, SpkSidebarSelector::RoleItemCategoryPageId, SpkStackedPages::PgQssTest);
#endif
//============ Sidebar entries END ============
CategoryWidget->addTopLevelItem(HomepageItem);
SidebarMgr->AddUnusableItem(CategoryParentItem);
CategoryWidget->addTopLevelItem(AppDetailsItem);
CategoryWidget->addTopLevelItem(CategoryParentItem);
CategoryWidget->addTopLevelItem(DownloadsItem);
CategoryWidget->addTopLevelItem(UiTestItem);
CategoryWidget->setFocusPolicy(Qt::NoFocus);
// Must be done after added into a view.
AppDetailsItem->setHidden(true); // Hide until we actually open up a Details page
CategoryParentItem->setExpanded(true);
// FIXMEIFPOSSIBLE: Fusion adds extra gradient.
// Details: https://forum.qt.io/topic/128190/fusion-style-kept-adding-an-extra-
// layer-of-gradient-to-my-selected-item-of-qtreewidget-even-with-qss
if(SpkUi::OldSystemStyle)
CategoryWidget->setStyle(SpkUi::OldSystemStyle);
SidebarMgr->BindCategoryWidget(CategoryWidget);
HorizontalDivide = new QHBoxLayout;
HorizontalDivide->setObjectName("spk_mw_divide_hlay");
HorizontalDivide->setSpacing(0);
HorizontalDivide->setContentsMargins(0, 0, 0, 0);
HorizontalDivide->setAlignment(Qt::AlignLeft);
if(!SpkUi::States::IsUsingDtkPlugin)
HorizontalDivide->addSpacing(SpkWindow::BorderWidth);
HorizontalDivide->addWidget(CategoryWidget);
HorizontalDivide->addWidget(Pager);
//============ Search Bar ============
SearchEdit = new SpkFocusLineEdit(this);
SearchEdit->setPlaceholderText(tr("Press Enter to search"));
SearchEdit->setFixedWidth(30);
SearchEdit->setFixedHeight(30);
SearchBarAnim = new QTimeLine(300, this);
SearchBarAnim->setDuration(300);
SearchBarAnim->setEasingCurve(QEasingCurve::OutExpo);
SearchBarAnim->setUpdateInterval(20);
ActClearSearchBar = SearchEdit->addAction(QIcon(":/icons/clear-input.svg"),
QLineEdit::TrailingPosition);
ActClearSearchBar->setVisible(false); // Invisible by default
ActSearchIcon = SearchEdit->addAction(QIcon(":/icons/search-mini.svg"), QLineEdit::LeadingPosition);
connect(SearchEdit, &SpkFocusLineEdit::focusGained,
[=](){
ActClearSearchBar->setVisible(true);
SearchBarAnim->setDirection(QTimeLine::Forward);
SearchBarAnim->start();
});
connect(SearchEdit, &SpkFocusLineEdit::focusLost,
[=](){
ActClearSearchBar->setVisible(false);
SearchBarAnim->setDirection(QTimeLine::Backward);
SearchBarAnim->start();
});
connect(SearchBarAnim, &QTimeLine::valueChanged,
[=](qreal v){
SearchEdit->setFixedWidth(static_cast<int>(250 * v) + 30);
});
connect(ActClearSearchBar, &QAction::triggered, [=](){ SearchEdit->clear(); });
connect(BtnBack, &QPushButton::clicked,
[=](){
SidebarMgr->GoBack();
BtnBack->setEnabled(false);
});
auto space = static_cast<SpkWindow*>(parent)->GetTitleBar()->GetUserSpace();
space->addSpacing(50);
space->addWidget(BtnDayNight);
space->addWidget(BtnSettings);
space->addWidget(BtnBack);
space->addWidget(SearchEdit);
space->addStretch();
//============ Pages =============
// Red-Black tree based map will be able to sort things. Just for convenience of ordering pages.
QMap<SpkStackedPages, QWidget*> sorter;
// Initialize pages
PageAppList = new SpkUi::SpkPageAppList(this);
PageAppList->setProperty("spk_pageid", SpkStackedPages::PgAppList);
sorter[PgAppList] = PageAppList;
PageAppDetails = new SpkUi::SpkPageAppDetails(this);
PageAppDetails->setProperty("spk_pageid", SpkStackedPages::PgAppDetails);
sorter[PgAppDetails] = PageAppDetails;
PageDownloads = new SpkUi::SpkPageDownloads(this);
PageDownloads->setProperty("spk_pageid", SpkStackedPages::PgDownloads);
sorter[PgDownloads] = PageDownloads;
PageSettings = new SpkUi::SpkPageSettings(this);
PageSettings->setProperty("spk_pageid", SpkStackedPages::PgSettings);
sorter[PgSettings] = PageSettings;
PageHome = new SpkUi::SpkPageHome(this);
PageSettings->setProperty("spk_pageid", SpkStackedPages::PgHomepage);
sorter[PgHomepage] = PageHome;
#ifndef NDEBUG // If only in debug mode should we initialize QSS test page
PageQssTest = new SpkUi::SpkPageUiTest(this);
PageQssTest->setProperty("spk_pageid", SpkStackedPages::PgQssTest);
sorter[PgQssTest] = PageQssTest;
#endif
for(auto i : sorter)
Pager->addWidget(i);
// Default page selection : homepage
HomepageItem->setSelected(true);
// Manually "activate" the default page item to make the sidebar tree know about default item
emit CategoryWidget->itemPressed(HomepageItem, 0);
setLayout(HorizontalDivide);
}

Some files were not shown because too many files have changed in this diff Show More