diff --git a/.workflow/dtk-build-commit-20220425.yml b/.workflow/dtk-build-commit-20220425.yml index b0f4f7d..807bb7c 100644 --- a/.workflow/dtk-build-commit-20220425.yml +++ b/.workflow/dtk-build-commit-20220425.yml @@ -32,8 +32,7 @@ stages: - cd .. - rm -rf dtk-old-bundle - 'mk-build-deps --install --tool "apt-get -o Debug::pkgProblemResolver=yes -y" ' - - sed -i 's/-j$(JOBS)/-j2/g' debian/rules - - dpkg-buildpackage -b -us -uc + - dpkg-buildpackage -j2 -b -us -uc - cd .. - ls -all - pwd diff --git a/.workflow/dtk-build-release-tag-20220425.yml b/.workflow/dtk-build-release-tag-20220425.yml index 06aa7b3..14fc27a 100644 --- a/.workflow/dtk-build-release-tag-20220425.yml +++ b/.workflow/dtk-build-release-tag-20220425.yml @@ -33,8 +33,7 @@ stages: - rm -rf dtk-old-bundle - '' - 'mk-build-deps --install --tool "apt-get -o Debug::pkgProblemResolver=yes -y" ' - - sed -i 's/-j$(JOBS)/-j2/g' debian/rules - - dpkg-buildpackage -b -us -uc + - dpkg-buildpackage -j2 -b -us -uc - cd .. - ls -all - pwd diff --git a/README.md b/README.md index 60facca..1fb54f7 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,14 @@ Then ```shell git clone https://gitee.com/deepin-community-store/spark-store.git cd spark-store -dpkg-buildpackage +dpkg-buildpackage -j +``` + +Or: +```shell +git clone https://gitee.com/deepin-community-store/spark-store.git +cd spark-store +./build_and_install.sh ``` diff --git a/README.zh.md b/README.zh.md index b9022b3..f5d6f71 100644 --- a/README.zh.md +++ b/README.zh.md @@ -34,13 +34,13 @@ Deepin V20/UOS 21 系统下, 安装依赖 ```shell -sudo apt install git qt5-default debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev fakeroot qtwayland5 qtwayland5-dev-tools dde-qt5wayland-plugin +sudo apt install git qt5-default debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev fakeroot qtwayland5 qtwayland5-dev-tools dde-qt5wayland-plugin libqt5svg5* ``` Ubuntu 22.04 系统下, 安装依赖 ```shell -sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev qtwayland5 qtwayland5-dev-tools +sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev qtwayland5 qtwayland5-dev-tools libqt5svg5* ``` @@ -48,9 +48,15 @@ sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a lib ```shell git clone https://gitee.com/deepin-community-store/spark-store.git cd spark-store -dpkg-buildpackage +dpkg-buildpackage -j ``` +或者: 编译并安装 +```shell +git clone https://gitee.com/deepin-community-store/spark-store.git +cd spark-store +./build_and_install.sh +``` ## 🚀 协作 diff --git a/build_and_install.sh b/build_and_install.sh new file mode 100755 index 0000000..f527a98 --- /dev/null +++ b/build_and_install.sh @@ -0,0 +1,24 @@ + +# Deepin V20/UOS 21 系统下, 安装依赖 + +# ```shell +# sudo apt install git qt5-default debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev fakeroot qtwayland5 qtwayland5-dev-tools dde-qt5wayland-plugin + +# ``` + +# Ubuntu 22.04 系统下, 安装依赖 +# ```shell +# sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev qtwayland5 qtwayland5-dev-tools + +# ``` + +echo "Deepin V20/UOS 21 系统下, 安装依赖" +echo "sudo apt install git qt5-default debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev fakeroot qtwayland5 qtwayland5-dev-tools dde-qt5wayland-plugin" + +echo "Ubuntu 22.04 系统下, 安装依赖" +echo "sudo apt install git qtbase5-dev debhelper pkg-config qtchooser libqt5core5a libqt5gui5 libqt5widgets5 libqt5network5 libqt5concurrent5 libdtkcore-dev libdtkgui-dev libdtkwidget-dev qttools5-private-dev libnotify-dev qtwebengine5-dev qtwayland5 qtwayland5-dev-tools" + +dpkg-buildpackage -j +sudo apt reinstall ../spark-store_*.deb + +rm ../spark-store_* \ No newline at end of file diff --git a/debian/changelog b/debian/changelog index 338df9f..9058b46 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,29 @@ +spark-store (4.2.3) stable; urgency=medium + * 修复: 编译依赖不全 + * 修复: prerm导致的dpkg崩溃 + * 新增: aptss 检查package配置增加sdu,store + * 新增: 一键编译并安装脚本 + * 新增: 后台安装结束后退出任务栏驻留 + + -- shenmo Fri, 30 Jan 2022 00:00:00 +0800 + +spark-store (4.2.3~test4) stable; urgency=medium + + * 修复: aptss 无法安装 + + -- shenmo Fri, 30 Jan 2022 00:00:00 +0800 + +spark-store (4.2.3~test3) stable; urgency=medium + + * 调整:打包时从 debian/changelog 自动获取构建版本号并写入关于窗口保证与deb一致 + * 新增:支持 DTK 5.6.4 关于对话框“版本特性”显示功能。目前只在deepin编译安装时开启 + * 修复:修复下载列表对话框中,点击某个 item 取消下载按钮后下载列表无法再次显示的问题 + * 修复:多个应用安装可能会出现某一个应用没有安装 + * 修复:修复下载按钮点击/双击/拖动时,主窗口动作与下载管理对话框动作同时触发问题 + * aptss 获取线路信息 转到从 d. 服务器获取 + + -- shenmo Fri, 30 Jan 2022 00:00:00 +0800 + spark-store (4.2.3~test2) stable; urgency=medium * 调整:开启安装包加固 @@ -5,6 +31,7 @@ spark-store (4.2.3~test2) stable; urgency=medium -- shenmo Fri, 30 Jan 2022 00:00:00 +0800 + spark-store (4.2.3~test1) stable; urgency=medium * 修复:因判断安装状态错误创建多个相同任务的bug diff --git a/debian/control b/debian/control index 29d980e..9f867ab 100644 --- a/debian/control +++ b/debian/control @@ -14,15 +14,16 @@ Build-Depends: libdtkcore-dev(>=5.0), libdtkgui-dev(>=5.0), libdtkwidget-dev(>=5.0), + libqt5svg5-dev, qttools5-private-dev, qtwebengine5-dev, qtwayland5, qtwayland5-dev-tools, gcc, g++ - -Standards-Version: 3.0 +Standards-Version: 4.0.0 Homepage: https://www.spark-app.store/ + Package: spark-store Architecture: any Depends:${shlibs:Depends}, ${misc:Depends}, diff --git a/debian/rules b/debian/rules index 45fb917..f30c24d 100755 --- a/debian/rules +++ b/debian/rules @@ -1,14 +1,14 @@ #!/usr/bin/make -f -export QT_SELECT=5 +export QT_SELECT = qt5 export DEB_BUILD_MAINT_OPTIONS = hardening=+all include /usr/share/dpkg/default.mk DEB_BUILD_ARCH ?= $(shell dpkg-architecture -qDEB_BUILD_ARCH) -DH_AUTO_ARGS = --parallel --buildsystem=qmake +DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) # Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 +#export DH_VERBOSE = 1 %: dh $@ --parallel @@ -18,20 +18,18 @@ override_dh_auto_clean: override_dh_auto_configure: mkdir -p $(CURDIR)/build - - dh_auto_configure MAKEFLAGS=-j$(JOBS) -- spark-store-project.pro \ + + qmake BUILD_VERSION=$(DEB_VERSION_UPSTREAM) spark-store-project.pro \ -spec linux-g++ CONFIG+=qtquickcompiler \ -o $(CURDIR)/build/ - override_dh_auto_build: - make -C $(CURDIR)/build -j$(JOBS) + make MAKEFLAGS="$(MAKEFLAGS)" -C $(CURDIR)/build override_dh_auto_install: make -C $(CURDIR)/build install \ INSTALL_ROOT=$(CURDIR)/debian/spark-store - # Ignore the dpkg-shlibdeps: warning (it uses none of the library's symbols) # Qt Mutidedia lib will ref to network libraray. override_dh_shlibdeps: diff --git a/debian/spark-store.postinst b/debian/spark-store.postinst index 1a2509a..c95810d 100755 --- a/debian/spark-store.postinst +++ b/debian/spark-store.postinst @@ -1,21 +1,17 @@ -#!/bin/sh +#!/bin/bash case "$1" in configure) + # Enable i386 arch + echo "Enabling i386 arch..." + dpkg --add-architecture i386 - # Enable i386 arch - echo "Enable i386 arch..." - dpkg --add-architecture i386 + # config for aptss + mkdir -p /etc/aptss/sources.list.d + ln -s -f /etc/apt/sources.list /etc/aptss/sources.list - # config for aptss - mkdir -p /etc/aptss/sources.list.d - ln -s -f /etc/apt/sources.list /etc/aptss/sources.list - - # Remove the sources.list file - if [ -e /etc/apt/sources.list.d/sparkstore.list ];then - rm /etc/apt/sources.list.d/sparkstore.list - fi - + # Remove the sources.list file + rm -f /etc/apt/sources.list.d/sparkstore.list # Check if /usr/local/bin existed mkdir -p /usr/local/bin @@ -28,33 +24,29 @@ case "$1" in ln -s -f /opt/durapps/spark-store/bin/ssaudit /usr/local/bin/ssaudit ln -s -f /opt/durapps/spark-store/bin/spark-dstore-patch /usr/local/bin/spark-dstore-patch ln -s -f /opt/durapps/spark-store/bin/aptss /usr/local/bin/ss-apt-fast - - ln -s -f /opt/durapps/spark-store/bin/aptss /usr/bin/aptss + + ln -s -f /opt/durapps/spark-store/bin/aptss /usr/bin/aptss # Create symbol links for SSINSTALL ln -s -f /opt/durapps/spark-store/bin/auto-install-policy/store.spark-app.ssinstall.policy /usr/share/polkit-1/actions/store.spark-app.ssinstall.policy + # Compile sender module echo "Compiling the Sender module..." - gcc -Wformat -Wformat-security -Werror=format-security /opt/durapps/spark-store/bin/ss-feedback/sender-d.sh.c -o /opt/durapps/spark-store/bin/ss-feedback/sender-d # Install key mkdir -p /tmp/spark-store-install/ - cp -f /opt/durapps/spark-store/bin/spark-store.asc /tmp/spark-store-install/spark-store.asc + cp -f /opt/durapps/spark-store/bin/spark-store.asc /tmp/spark-store-install/spark-store.asc gpg --dearmor /tmp/spark-store-install/spark-store.asc cp -f /tmp/spark-store-install/spark-store.asc.gpg /etc/apt/trusted.gpg.d/spark-store.gpg - - - # Run apt update to avoid users being fucked up by the non-exist dependency problem + # Run apt update to avoid users being fucked up by the non-exist dependency problem # Now abandoned as aptss now run ssupdate everytime #aptss ssupdate - # Start upgrade detect service systemctl enable spark-update-notifier - service spark-update-notifier start - + systemctl start spark-update-notifier # Update certain caches update-icon-caches /usr/share/icons/hicolor || true @@ -63,12 +55,10 @@ case "$1" in update-mime-database /usr/share/mime || true # Send email for statistics - # /tmp/spark-store-install/feedback.sh + #/tmp/spark-store-install/feedback.sh # Remove temp dir rm -rf /tmp/spark-store-install - - ;; triggered) diff --git a/debian/spark-store.postrm b/debian/spark-store.postrm index 03e5dc6..4b19c63 100644 --- a/debian/spark-store.postrm +++ b/debian/spark-store.postrm @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Update certain caches update-icon-caches /usr/share/icons/hicolor || true diff --git a/debian/spark-store.prerm b/debian/spark-store.prerm index e0a1457..2f28b69 100755 --- a/debian/spark-store.prerm +++ b/debian/spark-store.prerm @@ -1,48 +1,53 @@ -#!/bin/sh +#!/bin/bash +function notify-send() +{ + #Detect the user using such display + local user=$(who | awk '{print $1}' | head -n 1) -if [ "$1" = "remove" ] || [ "$1" = "purge" ];then -# Remove residual symbol links -rm /usr/local/bin/spark-store -rm /usr/local/bin/ssinstall -rm /usr/local/bin/ssaudit -rm /usr/local/bin/spark-dstore-patch -rm /usr/local/bin/ussinstall -rm /usr/local/bin/ussremove -rm /usr/local/bin/ss-apt-fast -rm /usr/bin/aptss + #Detect the id of the user + local uid=$(id -u $user) -rm -rf /etc/aptss/ + sudo -u $user DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus notify-send "$@" +} -# Remove Sender module -rm /opt/durapps/spark-store/bin/ss-feedback/sender-d +if [ "$1" = "remove" ] || [ "$1" = "purge" ] ; then + # Remove residual symbol links + rm -f /usr/local/bin/spark-store + rm -f /usr/local/bin/ssinstall + rm -f /usr/local/bin/ssaudit + rm -f /usr/local/bin/spark-dstore-patch + rm -f /usr/local/bin/ussinstall + rm -f /usr/local/bin/ussremove + rm -f /usr/local/bin/ss-apt-fast + rm -f /usr/bin/aptss -# Remove residual symbol links to stop upgrade detect if exist -if [ -e /etc/xdg/autostart/spark-update-notifier.desktop ];then -rm /etc/xdg/autostart/spark-update-notifier.desktop -fi + rm -rf /etc/aptss/ -# Shutdown services -service spark-update-notifier stop + # Remove Sender module + rm -f /opt/durapps/spark-store/bin/ss-feedback/sender-d -# Stop update detect service -systemctl disable spark-update-notifier + # Remove residual symbol links to stop upgrade detect + rm -f /etc/xdg/autostart/spark-update-notifier.desktop + # Shutdown services + systemctl stop spark-update-notifier + # Stop update detect service + systemctl disable spark-update-notifier + # Clean the auto install polkit file if exist + rm -f /usr/share/polkit-1/actions/store.spark-app.ssinstall.policy -# Clean the auto install polkit file if exist -if [ -f "/usr/share/polkit-1/actions/store.spark-app.ssinstall.policy" ] ; then - rm /usr/share/polkit-1/actions/store.spark-app.ssinstall.policy -fi - -# Remove gpg key file -if [ -f "/etc/apt/trusted.gpg.d/spark-store.gpg" ] ; then - rm /etc/apt/trusted.gpg.d/spark-store.gpg -fi - -apt-key del '9D9A A859 F750 24B1 A1EC E16E 0E41 D354 A29A 440C' - + # Remove gpg key file + rm -f /etc/apt/trusted.gpg.d/spark-store.gpg + apt-key del '9D9A A859 F750 24B1 A1EC E16E 0E41 D354 A29A 440C' else - -echo "非卸载操作,不进行配置清理" - + echo "非卸载操作,不进行配置清理" + + if [ ! -z "`pidof spark-store`" ];then + echo "关闭已有 spark-store.." + notify-send "正在升级星火商店" "请在升级结束后重启星火商店" -i spark-store + killall spark-store + else + echo "继续安装 spark-store.." + fi fi diff --git a/pkg/usr/share/dsg/org.deepin.dtkwidget.feature-display.json b/pkg/usr/share/dsg/org.deepin.dtkwidget.feature-display.json new file mode 100644 index 0000000..8d1bbee --- /dev/null +++ b/pkg/usr/share/dsg/org.deepin.dtkwidget.feature-display.json @@ -0,0 +1,26 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "featureUpdated": { + "value": false, + "serial": 0, + "flags": [], + "name": "Whether the application has new feature updates", + "name[zh_CN]": "配置应用的更新状态", + "description": "Configure the update status of the application", + "permissions": "readwrite", + "visibility": "public" + }, + "autoDisplayFeature": { + "value": false, + "serial": 0, + "flags": [], + "name": "The application automatically display new features once", + "name[zh_CN]": "配置应用是否自动展示一次新特性", + "description": "The application automatically display updated contents once", + "permissions": "readwrite", + "visibility": "public" + } + } +} \ No newline at end of file diff --git a/spark-store-project.pro b/spark-store-project.pro index 70e04be..1d8995f 100644 --- a/spark-store-project.pro +++ b/spark-store-project.pro @@ -7,15 +7,21 @@ TARGET = spark-store TEMPLATE = subdirs -CONFIG += ordered +#CONFIG += ordered CONFIG += wayland-compositor SUBDIRS += \ src/spark-dstore-patch \ src/spark-store.pro +# https://wiki.debian.org/Hardening +QMAKE_CFLAGS *= $(shell dpkg-buildflags --get CFLAGS) +QMAKE_CPPFLAGS *= $(shell dpkg-buildflags --get CPPFLAGS) +QMAKE_CXXFLAGS *= $(shell dpkg-buildflags --get CXXFLAGS) +QMAKE_LFLAGS *= $(shell dpkg-buildflags --get LDFLAGS) + # Update translation files -CONFIG(release, debug|release) { +CONFIG(release, debug | release) { system(bash $${PWD}/translate_update.sh) system(bash $${PWD}/translate_generation.sh) } @@ -66,9 +72,3 @@ INSTALLS += \ bash_completion \ polkit-1 # 暂时不添加 - -# https://wiki.debian.org/Hardening -QMAKE_CPPFLAGS *= $(shell dpkg-buildflags --get CPPFLAGS) -QMAKE_CFLAGS *= $(shell dpkg-buildflags --get CFLAGS) -QMAKE_CXXFLAGS *= $(shell dpkg-buildflags --get CXXFLAGS) -QMAKE_LFLAGS *= $(shell dpkg-buildflags --get LDFLAGS) \ No newline at end of file diff --git a/src/application.cpp b/src/application.cpp index 14853fe..f9928e7 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -1,10 +1,14 @@ #include "application.h" #include "mainwindow-dtk.h" +#include "utils/utils.h" #include #include #include #include +#if (DTK_VERSION >= DTK_VERSION_CHECK(5, 6, 4, 0)) +#include +#endif #include #include @@ -43,6 +47,9 @@ Application::Application(int &argc, char **argv) // 初始化日志模块 (默认日志位置 ~/.cache/spark-union/spark-store) DLogManager::registerConsoleAppender(); DLogManager::registerFileAppender(); + + // 获取版本特性信息 + m_featuresJsonObj = Utils::parseFeatureJsonFile(); } void Application::handleAboutAction() @@ -53,9 +60,21 @@ void Application::handleAboutAction() } initAboutDialog(); +#if (DTK_VERSION >= DTK_VERSION_CHECK(5, 6, 4, 0)) + initFeatureDisplayDialog(); // 初始化版本特性对话框 +#endif DApplication::handleAboutAction(); } +bool Application::notify(QObject *receiver, QEvent *event) +{ + if (m_mainWindow) { + m_mainWindow->notify(receiver, event); + } + + return DApplication::notify(receiver, event); +} + void Application::checkAppConfigLocation() { QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)); @@ -65,21 +84,18 @@ void Application::checkAppConfigLocation() } } -void Application::setVersionAndBuildDateTime(const QString &version, const QString &buildDateTime) +void Application::setBuildDateTime(const QString &buildDateTime) { - m_version = version; - m_buildDateTime = buildDateTime; - QSettings config(QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + "/config.ini", QSettings::IniFormat); - if (config.value("build/version").toString() != m_version) { + if (config.value("build/version").toString() != QString(APP_VERSION)) { qDebug() << "Spark Store has been updated!"; - config.setValue("build/version", m_version); - config.setValue("build/time", m_buildDateTime); + config.setValue("build/version", QString(APP_VERSION)); + config.setValue("build/time", buildDateTime); config.sync(); } - setApplicationVersion(DApplication::buildVersion(config.value("build/version").toString() + "-" + "Flamescion" + "-" + config.value("build/time").toString())); + setApplicationVersion(DApplication::buildVersion(QString(APP_VERSION) + "-" + "Flamescion" + "-" + buildDateTime)); } void Application::setMainWindow(MainWindow *window) @@ -89,6 +105,17 @@ void Application::setMainWindow(MainWindow *window) { initAboutDialog(); } +#if (DTK_VERSION >= DTK_VERSION_CHECK(5, 6, 4, 0)) + if (featureDisplayDialog() == nullptr || featureDisplayDialog()->parent() != m_mainWindow) + { + initFeatureDisplayDialog(); // 初始化版本特性对话框 + } +#endif +} + +MainWindow *Application::mainWindow() +{ + return m_mainWindow; } void Application::initAboutDialog() @@ -109,6 +136,9 @@ void Application::initAboutDialog() dialog->setProductName(productName()); dialog->setProductIcon(productIcon()); dialog->setVersion(translate("DAboutDialog", "Version: %1").arg(applicationVersion())); +#if (DTK_VERSION >= DTK_VERSION_CHECK(5, 6, 4, 0)) + dialog->setVersion(applicationVersion()); +#endif // 根据 shenmo 要求,不显示组织 Logo // dialog->setCompanyLogo(QPixmap(":/icon/Logo-Spark.png")); dialog->setCompanyLogo(QPixmap()); @@ -118,9 +148,70 @@ void Application::initAboutDialog() dialog->setLicense(translate("DAboutDialog", "%1 is released under %2").arg(productName()).arg(applicationLicense())); setAboutDialog(dialog); - connect(aboutDialog(), &DAboutDialog::destroyed, this, [=] { + connect(aboutDialog(), &DAboutDialog::destroyed, this, [=]() { setAboutDialog(nullptr); }); dialog->hide(); } + +#if (DTK_VERSION >= DTK_VERSION_CHECK(5, 6, 4, 0)) +/** + * @brief Application::initFeatureDisplayDialog 初始化版本特性对话框 + */ +void Application::initFeatureDisplayDialog() +{ + if (featureDisplayDialog()) + { + featureDisplayDialog()->deleteLater(); + setFeatureDisplayDialog(nullptr); + } + + // 自定义 DFeatureDisplayDialog + DFeatureDisplayDialog *dialog = new DFeatureDisplayDialog(m_mainWindow); + // 标题 + dialog->setTitle(m_featuresJsonObj.value("title").toString()); + // NOTE: json 文件中支持多语言;考虑到维护性,不放入翻译文件处理 + if (m_featuresJsonObj.contains(QString("title[%1]").arg(QLocale::system().name()))) + { + dialog->setTitle(m_featuresJsonObj.value(QString("title[%1]").arg(QLocale::system().name())).toString()); + } + + // 特性项 + QList items; + foreach (const QJsonValue &jsonValue, m_featuresJsonObj.value("items").toArray()) + { + QJsonObject jsonObj = jsonValue.toObject(); + QString name = jsonObj.value("name").toString(); + if (jsonObj.contains(QString("name[%1]").arg(QLocale::system().name()))) + { + name = jsonObj.value(QString("name[%1]").arg(QLocale::system().name())).toString(); + } + QString description = jsonObj.value("description").toString(); + if (jsonObj.contains(QString("description[%1]").arg(QLocale::system().name()))) + { + description = jsonObj.value(QString("description[%1]").arg(QLocale::system().name())).toString(); + } + + DFeatureItem *item = new DFeatureItem(QIcon::fromTheme("spark-store"), name, description, dialog); + items.append(item); + } + dialog->addItems(items); // NOTE: 也支持 addItem 依次添加单个 item + + // “了解更多”链接按钮 + dialog->setLinkUrl(m_featuresJsonObj.value("linkUrl").toString()); + dialog->setLinkButtonVisible(m_featuresJsonObj.value("linkButtonVisible").toBool()); + + setFeatureDisplayDialog(dialog); + connect(featureDisplayDialog(), &DFeatureDisplayDialog::destroyed, this, [=]() { + setFeatureDisplayDialog(nullptr); + }); +#if (DTK_VERSION >= DTK_VERSION_CHECK(5, 6, 4, 0)) + connect(aboutDialog(), &DAboutDialog::featureActivated, this, [=]() { + featureDisplayDialog()->show(); + }); +#endif + + dialog->hide(); +} +#endif diff --git a/src/application.h b/src/application.h index 0c7aa8b..de66a7e 100644 --- a/src/application.h +++ b/src/application.h @@ -3,6 +3,8 @@ #include +#include + DWIDGET_USE_NAMESPACE class MainWindow; @@ -13,18 +15,23 @@ class Application : public DApplication public: Application(int &argc, char **argv); void handleAboutAction() override; + bool notify(QObject *receiver, QEvent *event) override; static void checkAppConfigLocation(); - void setVersionAndBuildDateTime(const QString &version, const QString &buildDateTime); + void setBuildDateTime(const QString &buildDateTime); + void setMainWindow(MainWindow *window); + MainWindow *mainWindow(); private: void initAboutDialog(); +#if (DTK_VERSION >= DTK_VERSION_CHECK(5, 6, 4, 0)) + void initFeatureDisplayDialog(); +#endif private: - QString m_version; - QString m_buildDateTime; + QJsonObject m_featuresJsonObj; MainWindow *m_mainWindow = nullptr; }; diff --git a/src/assets/assets.qrc b/src/assets/assets.qrc index ef4b248..ed35fdf 100644 --- a/src/assets/assets.qrc +++ b/src/assets/assets.qrc @@ -44,6 +44,7 @@ icon/light/text.svg icon/light/update.svg icon/logo.svg + json/features.json tags/a2d-small.png tags/a2d.png tags/community-small.png diff --git a/src/assets/json/features.json b/src/assets/json/features.json new file mode 100644 index 0000000..55709de --- /dev/null +++ b/src/assets/json/features.json @@ -0,0 +1,25 @@ +{ + "title": "Features", + "title[zh_CN]": "版本特性", + "items": [ + { + "icon": "/usr/share/icons/hicolor/scalable/apps/spark-store.svg", + "name": "Feature 1", + "name[zh_CN]": "特性 1", + "description": "Please click the learn more button to check", + "description[zh_CN]": "请点击 了解更多 按钮来获取特性" + }, + { + "icon": ":/icon/logo.svg", + "name": "Feature 2", + "description": "Feature 2 detailed description..." + }, + { + "icon": "spark-store", + "name": "Fix 1", + "description": "Fix 1 detailed description..." + } + ], + "linkUrl": "https://gitee.com/deepin-community-store/spark-store/releases/4.2.3test3", + "linkButtonVisible": true +} diff --git a/src/backend/downloadworker.cpp b/src/backend/downloadworker.cpp index 7bbe142..8b70540 100644 --- a/src/backend/downloadworker.cpp +++ b/src/backend/downloadworker.cpp @@ -1,9 +1,7 @@ #include "downloadworker.h" -#include #include #include -#include #include #include diff --git a/src/backend/downloadworker.h b/src/backend/downloadworker.h index 83061c1..6b7110e 100644 --- a/src/backend/downloadworker.h +++ b/src/backend/downloadworker.h @@ -2,9 +2,7 @@ #define DOWNLOADWORKER_H #include -#include -#include -#include +#include class DownloadController : public QObject { @@ -19,23 +17,19 @@ public: qint64 getFileSize(const QString& url); QString replaceDomain(const QString& url, const QString domain); +signals: + void errorOccur(const QString& msg); + void downloadProcess(QString, qint64, qint64); + void downloadFinished(); + private: int threadNum; qint64 pidNumber = -1; QString filename; qint64 fileSize; QVector> ranges; - QFile *file; bool finished = false; QVector domains; - - - -signals: - void errorOccur(const QString& msg); - void downloadProcess(QString, qint64, qint64); - void downloadFinished(); - }; #endif // FILEDOWNLOADWORKER_H diff --git a/src/main.cpp b/src/main.cpp index f2162bc..14e151d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ #include #include #include +#include DCORE_USE_NAMESPACE DWIDGET_USE_NAMESPACE @@ -18,7 +19,6 @@ DWIDGET_USE_NAMESPACE int main(int argc, char *argv[]) { // Get build time - static const QString version = "4.2.3"; static const QDate buildDate = QLocale(QLocale::English).toDate(QString(__DATE__).replace(" ", " 0"), "MMM dd yyyy"); static const QTime buildTime = QTime::fromString(__TIME__, "hh:mm:ss"); static const QString buildDateTime = buildDate.toString("yyyy.MM.dd") + "-" + buildTime.toString("hh:mm:ss"); @@ -36,15 +36,47 @@ int main(int argc, char *argv[]) // 龙芯机器配置,使得 DApplication 能正确加载 QTWEBENGINE qputenv("DTK_FORCE_RASTER_WIDGETS", "FALSE"); -// qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--disable-features=UseModernMediaControls"); -// qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--disable-web-security"); + // qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--disable-features=UseModernMediaControls"); + // qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--disable-web-security"); + + // 浏览器开启 GPU 支持 #ifdef __sw_64__ - qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--ignore-gpu-blocklist --enable-gpu-rasterization --enable-native-gpu-memory-buffers --enable-accelerated-video-decode --no-sandbox"); -#else - qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--ignore-gpu-blocklist --enable-gpu-rasterization --enable-native-gpu-memory-buffers --enable-accelerated-video-decode"); + qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--no-sandbox"); #endif + /** + * FIXME: 对于麒麟 CPU 设备,调用 QtWebEngine 会导致客户端崩溃; + * 暂时不对 CPU 进行判断,对 wayland 环境下统一处理 + */ + if (Utils::isWayland()) { + QString env = QString::fromUtf8(qgetenv("QTWEBENGINE_CHROMIUM_FLAGS")); + env = env.trimmed(); + /** + * NOTE: 参考帮助手册代码,对于麒麟 CPU 设备, + * --disable-gpu 保证 wayland 环境下网页正常显示 + * --single-process 避免 wayland 环境下 QtWebEngine 崩溃(可选) + */ + env += " --disable-gpu"; + qputenv("QTWEBENGINE_CHROMIUM_FLAGS", env.trimmed().toUtf8()); + + /** + * NOTE: 参考帮助手册代码,对于麒麟 CPU 设备, + * 避免 wayland 环境下 QtWebEngine 崩溃 + */ + qputenv("QT_WAYLAND_SHELL_INTEGRATION", "kwayland-shell"); + QSurfaceFormat format; + format.setRenderableType(QSurfaceFormat::OpenGLES); + QSurfaceFormat::setDefaultFormat(format); + + /** + * NOTE: https://zhuanlan.zhihu.com/p/550285855 + * 避免 wayland 环境下从 QtWebEngine 后退回到 QWidget 时黑屏闪烁 + */ + qputenv("QMLSCENE_DEVICE", "softwarecontext"); + DApplication::setAttribute(Qt::AA_UseSoftwareOpenGL); + } + DApplication::setAttribute(Qt::AA_EnableHighDpiScaling); // 开启 Hidpi 支持 // 强制使用 DTK 平台插件 @@ -59,7 +91,7 @@ int main(int argc, char *argv[]) int fakeArgc = argc + 2; // QCoreApplication 的 argc 要用引用,避免 c++ 编译器优化 Application a(fakeArgc, fakeArgs.data()); // 设置版本和构建时间 - a.setVersionAndBuildDateTime(version, buildDateTime); + a.setBuildDateTime(buildDateTime); // 限制单实例运行 if (!a.setSingleInstance("spark-store")) diff --git a/src/mainwindow-dtk.cpp b/src/mainwindow-dtk.cpp index 899617a..9ba4da2 100644 --- a/src/mainwindow-dtk.cpp +++ b/src/mainwindow-dtk.cpp @@ -3,6 +3,7 @@ #include "utils/widgetanimation.h" #include "widgets/common/progressbutton.h" #include "widgets/downloadlistwidget.h" +#include "widgets/common/downloaditem.h" #include "dbus/dbussparkstoreservice.h" #include "application.h" @@ -10,6 +11,7 @@ #include #include +#include #include #include @@ -102,6 +104,22 @@ void MainWindow::openUrl(const QString &url) } } +bool MainWindow::isCloseWindowAnimation() +{ + return closeWindowAnimation; +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + // 判断下载任务数量,如果没有要下载的,就直接退出主程序 + if(!downloadlistwidget->isDownloadInProcess()){ + // 已经全部下载完成 + qApp->quit(); + } + + BaseWidgetOpacity::closeEvent(event); +} + void MainWindow::initUI() { setWindowTitle(QObject::tr("Spark Store")); @@ -132,6 +150,9 @@ void MainWindow::initTitleBar() searchEdit->setPlaceholderText(tr("Search or enter spk://")); downloadButton = new ProgressButton(ui->titlebar); + downloadButton->setDownloadListWidget(downloadlistwidget); + downloadButton->setFocusPolicy(Qt::FocusPolicy::ClickFocus); + downloadlistwidget->setFocusProxy(downloadButton); QWidget *w_titlebar = new QWidget(ui->titlebar); QHBoxLayout *ly_titlebar = new QHBoxLayout(w_titlebar); @@ -297,14 +318,6 @@ void MainWindow::initConnections() ui->appintopage->setTheme(themeType == DGuiApplicationHelper::DarkType); ui->settingspage->setTheme(themeType == DGuiApplicationHelper::DarkType); }); - connect(downloadButton, &ProgressButton::clicked, [=]() - { - QPoint pos; - pos.setX(downloadButton->mapToGlobal(QPoint(0, 0)).x() + downloadButton->width() / 2 - downloadlistwidget->width() / 2); - pos.setY(downloadButton->mapToGlobal(QPoint(0, 0)).y() + downloadButton->height() + 5); - downloadlistwidget->m_move(pos.x(), pos.y()); - downloadlistwidget->show(); }); - // appintopage按下下载按钮时标题栏下载列表按钮抖动 connect(ui->appintopage, &AppIntoPage::clickedDownloadBtn, [=]() { @@ -421,6 +434,35 @@ void MainWindow::updateUi(int now) switchPage(AppPageApplist); } +void MainWindow::notify(QObject *receiver, QEvent *event) +{ + if (!receiver) { + return; + } + + Dtk::Widget::DStyle *o_ptr = qobject_cast(receiver); + if (o_ptr) { + return; + } + + if (receiver->inherits("QWidgetWindow") + || receiver->inherits("QStyleSheetStyle")) { + return; + } + + if (event->type() == QEvent::FocusIn) { + QList list = downloadButton->findChildren(QString(), Qt::FindChildrenRecursively); + list << downloadlistwidget->findChildren(QString(), Qt::FindChildrenRecursively); + if (receiver != downloadButton && receiver != downloadlistwidget && !list.contains(receiver)) { + downloadlistwidget->hide(); + } + } else if (event->type() == QEvent::FocusOut) { + if (!downloadlistwidget->isActiveWindow() && !isActiveWindow()) { + downloadlistwidget->hide(); + } + } +} + void MainWindow::on_pushButton_14_clicked() { // Check UOS diff --git a/src/mainwindow-dtk.h b/src/mainwindow-dtk.h index 8b1ca60..11fd60e 100644 --- a/src/mainwindow-dtk.h +++ b/src/mainwindow-dtk.h @@ -25,10 +25,15 @@ class MainWindow : public BaseWidgetOpacity public: explicit MainWindow(QWidget *parent = nullptr); - ~MainWindow(); + ~MainWindow() override; void openUrl(const QString &url); + bool isCloseWindowAnimation(); + +protected: + void closeEvent(QCloseEvent *event) override; + private: void initUI(); void initTitleBar(); @@ -41,6 +46,9 @@ private: void switchPage(int now); void updateUi(int now); +public slots: + void notify(QObject *receiver, QEvent *event); + private slots: //接受来自dbus的url void onGetUrl(const QString &url); diff --git a/src/pages/appintopage.cpp b/src/pages/appintopage.cpp index 783f97d..1bd59f5 100644 --- a/src/pages/appintopage.cpp +++ b/src/pages/appintopage.cpp @@ -2,8 +2,10 @@ #include "ui_appintopage.h" #include "backend/sparkapi.h" #include "widgets/downloadlistwidget.h" +#include "widgets/common/downloaditem.h" #include "backend/image_show.h" #include "application.h" +#include "utils/utils.h" #include #include diff --git a/src/pages/appintopage.h b/src/pages/appintopage.h index f696e7a..5541d38 100644 --- a/src/pages/appintopage.h +++ b/src/pages/appintopage.h @@ -1,8 +1,6 @@ #ifndef APPINTOPAGE_H #define APPINTOPAGE_H -#include "utils/utils.h" - #include #include #include diff --git a/src/spark-store.pro b/src/spark-store.pro index 952a908..97b597f 100644 --- a/src/spark-store.pro +++ b/src/spark-store.pro @@ -22,8 +22,13 @@ DEFINES += QT_DEPRECATED_WARNINGS # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 +# Get build version from qmake +VERSION = $$BUILD_VERSION +isEmpty(VERSION): VERSION = 4.0.0 +DEFINES += APP_VERSION=\\\"'$${VERSION}'\\\" + # Disable qWarning / qDebug output in Release -# CONFIG(release, debug|release): DEFINES += QT_NO_WARNING_OUTPUT QT_NO_DEBUG_OUTPUT +#CONFIG(release, debug | release): DEFINES += QT_NO_WARNING_OUTPUT QT_NO_DEBUG_OUTPUT CONFIG += c++11 link_pkgconfig PKGCONFIG += dtkcore dtkgui dtkwidget diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index c832f91..e502d8e 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #define UOSDeveloperModeFile "/var/lib/deepin/developer-mode/enabled" @@ -182,3 +183,33 @@ void Utils::checkUOSDeveloperMode() file.close(); config.sync(); // 写入更改至 config.ini,并同步最新内容 } + +/** + * @brief Utils::parseFeatureJsonFile 解析版本特性 json 文件 + * @return 返回 QJsonObject + */ +QJsonObject Utils::parseFeatureJsonFile() +{ + QFile file(":/json/features.json"); + if (!file.open(QFile::ReadOnly)) + { + qWarning() << Q_FUNC_INFO << "features.json open failed"; + return QJsonObject(); + } + + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll(), &error); + if (error.error != QJsonParseError::NoError || jsonDoc.isNull()) + { + qWarning() << Q_FUNC_INFO << "features.json validate failed:" << error.errorString(); + return QJsonObject(); + } + + if (jsonDoc.isEmpty() || !jsonDoc.isObject()) + { + qWarning() << Q_FUNC_INFO << "features jsonDoc parse failed:" << jsonDoc; + return QJsonObject(); + } + + return jsonDoc.object(); +} diff --git a/src/utils/utils.h b/src/utils/utils.h index 0797029..154e9b8 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -2,6 +2,7 @@ #define UTILS_H #include +#include class Utils { @@ -13,6 +14,7 @@ public: static bool isUOS(); static void setQPAPlatform(); static void checkUOSDeveloperMode(); + static QJsonObject parseFeatureJsonFile(); }; #endif // UTILS_H diff --git a/src/widgets/base/basewidgetopacity.cpp b/src/widgets/base/basewidgetopacity.cpp index 3874b7e..712aade 100644 --- a/src/widgets/base/basewidgetopacity.cpp +++ b/src/widgets/base/basewidgetopacity.cpp @@ -43,6 +43,7 @@ void BaseWidgetOpacity::closeEvent(QCloseEvent *event) bool isWayland = Utils::isWayland(); if (isWayland) { + closeWindowAnimation = true; return DBlurEffectWidget::closeEvent(event); } diff --git a/src/widgets/common/downloaditem.cpp b/src/widgets/common/downloaditem.cpp index 8aceda5..8142790 100644 --- a/src/widgets/common/downloaditem.cpp +++ b/src/widgets/common/downloaditem.cpp @@ -61,8 +61,21 @@ QString DownloadItem::getName() return ui->label_filename->text(); } -void DownloadItem::readyInstall() + +/*************************************************************** + * @brief 告知界面,准备安装 + * @param + * @note 如果正在安装,返回-1 + * @Sample usage: DownloadItem::install(0); + **************************************************************/ +int DownloadItem::readyInstall() { + // 检查是否正在安装,如果是返回错误 -1 + if (isInstall) + { + return -1; + } + if (!close) { ui->progressBar->hide(); @@ -70,7 +83,9 @@ void DownloadItem::readyInstall() ui->pushButton_install->show(); DownloadItem::install(0); ui->pushButton_2->hide(); + return 1; } + return 0; } void DownloadItem::setFileName(QString fileName) @@ -93,6 +108,12 @@ void DownloadItem::setSpeed(QString s) speed = s; } +/*************************************************************** + * @brief 安装当前应用 + * @param int t, t为安装方式,可以为 0,1,2 + * @note 执行这个函数时,需要已经检查是否可以安装,但该函数仍然会再检测一次! + * @Sample usage: DownloadItem::install(0); + **************************************************************/ void DownloadItem::install(int t) { if (!isInstall) @@ -142,6 +163,12 @@ void DownloadItem::on_pushButton_3_clicked() output_w->show(); } +/*************************************************************** + * @brief 实际安装应用 + * @param int t, t为安装方式,可以为 0,1,2 + * @note 备注 + * @Sample usage: slotAsyncInstall(0); + **************************************************************/ void DownloadItem::slotAsyncInstall(int t) { QProcess installer; diff --git a/src/widgets/common/downloaditem.h b/src/widgets/common/downloaditem.h index 05c9a3d..b00c3ee 100644 --- a/src/widgets/common/downloaditem.h +++ b/src/widgets/common/downloaditem.h @@ -34,7 +34,7 @@ public: void setMax(qint64); void setName(QString); QString getName(); - void readyInstall(); + int readyInstall(); void setFileName(QString); void seticon(const QPixmap); diff --git a/src/widgets/common/progressbutton.cpp b/src/widgets/common/progressbutton.cpp index 81ed80d..41a140a 100644 --- a/src/widgets/common/progressbutton.cpp +++ b/src/widgets/common/progressbutton.cpp @@ -1,20 +1,20 @@ #include "progressbutton.h" +#include "widgets/downloadlistwidget.h" + #include #include -#include -#include -#include +#include #include + ProgressButton::ProgressButton(QWidget *parent) : QWidget{parent} { // this->setWindowFlags(Qt::FramelessWindowHint); // this->setAttribute(Qt::WA_TranslucentBackground, true); - setMinimumWidth(36); - setMinimumHeight(36); + setMinimumSize(36, 36); + svgPath = ""; backColor = Qt::transparent; - setMouseTracking(true); connect(this, &ProgressButton::startProcessing, this, &ProgressButton::operationProcessing, Qt::QueuedConnection); } @@ -23,69 +23,6 @@ ProgressButton::~ProgressButton() { } -void ProgressButton::paintEvent(QPaintEvent *event) -{ - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing, true); - auto rect = event->rect(); - - if (buttonState == state::normal || buttonState == state::hover) - { - auto radiu = (rect.height() - 6) / 2; - painter.translate(rect.center()); - painter.setPen(Qt::transparent); - painter.setBrush(QColor(buttonState == state::normal ? color : color.darker())); - // painter.drawEllipse(QPoint(0,0),radiu,radiu); - - // radiu -= 3; - painter.setBrush(backColor); - painter.drawEllipse(QPoint(0, 0), radiu, radiu); - - QSvgRenderer m_svgRender; - m_svgRender.load(svgPath); - m_svgRender.render(&painter, QRectF(-radiu / 2, -radiu / 2, radiu, radiu)); - } - else if (buttonState == state::openProgress) - { - painter.translate(rect.center()); - auto radiu = (rect.height() - 6) / 2 - 3; - painter.setBrush(backColor); - painter.setPen(QPen(backColor, 3)); - painter.drawEllipse(QPoint(0, 0), radiu, radiu); - - painter.setPen(QPen(backColor, 3)); - - QSvgRenderer m_svgRender; - m_svgRender.load(svgPath); - m_svgRender.render(&painter, QRectF(-radiu / 2, -radiu / 2, radiu, radiu)); - - QRect rect = QRect(-radiu, -radiu, - radiu * 2, radiu * 2); - - painter.setPen(QPen(color.darker(100), 3)); - auto angle = progress * 360 / 100; - painter.drawArc(rect.adjusted(-3, -3, 3, 3), 90 * 16, -static_cast(angle * 16)); - } - else if (buttonState == state::closeProgress) - { - auto radiu = (rect.height() - 6) / 2; - painter.translate(rect.center()); - painter.setPen(Qt::transparent); - painter.setBrush(QColor(0, 0, 0, 63)); - painter.drawEllipse(QPoint(0, 0), radiu, radiu); - - radiu -= 3; - painter.setBrush(backColor); - painter.drawEllipse(QPoint(0, 0), radiu, radiu); - - painter.setPen(QPen(color, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); - painter.drawLine(QPoint(-radiu / 3, 0), - QPoint(-radiu / 5, radiu / 3)); - painter.drawLine(QPoint(-radiu / 5, radiu / 3), - QPoint(radiu / 4, -radiu / 4)); - } -} - void ProgressButton::setProgress(int progress) { buttonState = state::openProgress; @@ -107,6 +44,11 @@ void ProgressButton::setProgress(int progress) update(); } +void ProgressButton::setDownloadListWidget(DownloadListWidget *widget) +{ + m_downloadListWidget = widget; +} + void ProgressButton::setIcon(QString svgPATH) { svgPath = svgPATH; @@ -125,17 +67,15 @@ void ProgressButton::setColor(QColor color) update(); } -void ProgressButton::leaveEvent(QEvent *event) +void ProgressButton::mousePressEvent(QMouseEvent *event) { - if (buttonState == state::hover) - { - buttonState = state::normal; - update(); - } - QWidget::leaveEvent(event); + m_mouseMoved = false; + m_isDownloadListWidgetVisible = m_downloadListWidget->isVisible(); + m_downloadListWidget->hide(); + QWidget::mousePressEvent(event); } -void ProgressButton::mousePressEvent(QMouseEvent *event) +void ProgressButton::mouseReleaseEvent(QMouseEvent *event) { if (buttonState == state::hover || buttonState == state::normal) { @@ -146,8 +86,109 @@ void ProgressButton::mousePressEvent(QMouseEvent *event) { update(); } - emit clicked(); - QWidget::mousePressEvent(event); + + if (m_mouseMoved) { + return QWidget::mouseReleaseEvent(event); + } + + if (m_isDownloadListWidgetVisible) { + m_downloadListWidget->hide(); + } else { + QPoint pos(this->mapToGlobal(QPoint(0, 0))); + pos += QPoint(width() / 2 - m_downloadListWidget->width() / 2, height() + 5); + m_downloadListWidget->m_move(pos.x(), pos.y()); + m_downloadListWidget->setWindowState(windowState() & Qt::WindowState::WindowActive); + m_downloadListWidget->activateWindow(); + m_downloadListWidget->show(); + m_downloadListWidget->raise(); + } + m_isDownloadListWidgetVisible = m_downloadListWidget->isVisible(); + QWidget::mouseReleaseEvent(event); +} + +void ProgressButton::mouseDoubleClickEvent(QMouseEvent *event) +{ + event->accept(); +} + +void ProgressButton::mouseMoveEvent(QMouseEvent *event) +{ + m_mouseMoved = true; + QWidget::mouseMoveEvent(event); +} + +void ProgressButton::leaveEvent(QEvent *event) +{ + if (buttonState == state::hover) + { + buttonState = state::normal; + update(); + } + QWidget::leaveEvent(event); +} + +void ProgressButton::paintEvent(QPaintEvent *event) +{ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + QRect rect = event->rect(); + + if (buttonState == state::normal || buttonState == state::hover) + { + int radius = (rect.height() - 6) / 2; + painter.translate(rect.center()); + painter.setPen(Qt::transparent); + painter.setBrush(QColor(buttonState == state::normal ? color : color.darker())); + // painter.drawEllipse(QPoint(0, 0), radius, radius); + + // radiu -= 3; + painter.setBrush(backColor); + painter.drawEllipse(QPoint(0, 0), radius, radius); + + QSvgRenderer m_svgRender; + m_svgRender.load(svgPath); + m_svgRender.render(&painter, QRectF(-radius / 2, -radius / 2, radius, radius)); + } + else if (buttonState == state::openProgress) + { + painter.translate(rect.center()); + int radius = (rect.height() - 6) / 2 - 3; + painter.setBrush(backColor); + painter.setPen(QPen(backColor, 3)); + painter.drawEllipse(QPoint(0, 0), radius, radius); + + painter.setPen(QPen(backColor, 3)); + + QSvgRenderer m_svgRender; + m_svgRender.load(svgPath); + m_svgRender.render(&painter, QRectF(-radius / 2, -radius / 2, radius, radius)); + + QRect rect = QRect(-radius, -radius, + radius * 2, radius * 2); + + painter.setPen(QPen(color.darker(100), 3)); + qreal angle = progress * 360 / 100 * 1.0; + painter.drawArc(rect.adjusted(-3, -3, 3, 3), 90 * 16, -qIntCast(angle * 16)); + } + else if (buttonState == state::closeProgress) + { + auto radius = (rect.height() - 6) / 2; + painter.translate(rect.center()); + painter.setPen(Qt::transparent); + painter.setBrush(QColor(0, 0, 0, 63)); + painter.drawEllipse(QPoint(0, 0), radius, radius); + + radius -= 3; + painter.setBrush(backColor); + painter.drawEllipse(QPoint(0, 0), radius, radius); + + painter.setPen(QPen(color, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); + painter.drawLine(QPoint(-radius / 3, 0), + QPoint(-radius / 5, radius / 3)); + painter.drawLine(QPoint(-radius / 5, radius / 3), + QPoint(radius / 4, -radius / 4)); + } + QWidget::paintEvent(event); } void ProgressButton::operationProcessing() @@ -156,16 +197,16 @@ void ProgressButton::operationProcessing() const int RADIUS = 60; WaterDrop::WaterDrop(QWidget *parent) - : QWidget(parent), m_waterDropAnimation(nullptr), m_animationRadius(0) + : QWidget(parent) + , m_waterDropAnimation(new QVariantAnimation(this)) + , m_animationRadius(0) { this->setFixedSize(QSize(RADIUS * 2, RADIUS * 2)); // this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool); // this->setAttribute(Qt::WA_TranslucentBackground); // this->setAttribute(Qt::WA_DeleteOnClose); - m_waterDropAnimation = new QVariantAnimation(this); - // m_waterDropAnimation->setEasingCurve(QEasingCurve(static_cast(QRandomGenerator::global()->bounded(40)))); - connect(m_waterDropAnimation, &QVariantAnimation::finished, this, &WaterDrop::deleteLater); + // m_waterDropAnimation->setEasingCurve(QEasingCurve(static_cast(QRandomGenerator::global()->bounded(40)))); } // 把鼠标点击的点转换为圆心点坐标 @@ -191,8 +232,7 @@ void WaterDrop::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); - QPen pen; - pen.setColor(QColor(0xffffff80)); + QPen pen(QBrush(QColor("#ffff80")), 5.0); pen.setWidth(5); painter.setPen(pen); painter.drawEllipse(event->rect().center(), m_animationRadius, m_animationRadius); @@ -200,7 +240,7 @@ void WaterDrop::paintEvent(QPaintEvent *event) QWidget::paintEvent(event); } -void WaterDrop::onRadiusChanged(QVariant value) +void WaterDrop::onRadiusChanged(const QVariant &value) { m_animationRadius = value.toInt(); update(); diff --git a/src/widgets/common/progressbutton.h b/src/widgets/common/progressbutton.h index cf18391..1762600 100644 --- a/src/widgets/common/progressbutton.h +++ b/src/widgets/common/progressbutton.h @@ -1,53 +1,62 @@ #ifndef PROGRESSBUTTON_H #define PROGRESSBUTTON_H - -#include - -#include - +#include #include -#include -#include -#include -#include - +#include +class DownloadListWidget; class ProgressButton : public QWidget { Q_OBJECT + public: - ProgressButton(QWidget *parent = nullptr); + explicit ProgressButton(QWidget *parent = nullptr); + ~ProgressButton() override; + void setIcon(QString svgPATH); void setBackgroundColor(QColor color); void setColor(QColor color); void setProgress(int progress); - ~ProgressButton(); + + void setDownloadListWidget(DownloadListWidget *widget); + +protected: + void mousePressEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void leaveEvent(QEvent *event) override; + void paintEvent(QPaintEvent *event) override; + signals: void startProcessing(); void clicked(); -protected: - void paintEvent(QPaintEvent *event)override; - void leaveEvent(QEvent *event)override; - void mousePressEvent(QMouseEvent *event)override; +private slots: + void operationProcessing(); private: - enum class state + enum state { normal, hover, openProgress, closeProgress, recovery - } - buttonState{state::normal}; + }; + + DownloadListWidget *m_downloadListWidget = nullptr; + + state buttonState{state::normal}; QColor backColor; QColor color; QString svgPath; int widthChangeValue{0}; - void operationProcessing(); int progress{0};//处理百分比 + + bool m_mouseMoved = false; + bool m_isDownloadListWidgetVisible = true; }; class WaterDrop : public QWidget @@ -55,19 +64,19 @@ class WaterDrop : public QWidget Q_OBJECT public: - WaterDrop(QWidget *parent = Q_NULLPTR); + explicit WaterDrop(QWidget *parent = nullptr); void show(); void move(const QPoint &point); -private: +protected: void paintEvent(QPaintEvent *event); - void onRadiusChanged(QVariant value); + +private slots: + void onRadiusChanged(const QVariant &value); private: - class QVariantAnimation* m_waterDropAnimation; + QVariantAnimation *m_waterDropAnimation = nullptr; int m_animationRadius; }; - - #endif // PROGRESSBUTTON_H diff --git a/src/widgets/downloadlistwidget.cpp b/src/widgets/downloadlistwidget.cpp index 9aaa2d4..8cd666c 100644 --- a/src/widgets/downloadlistwidget.cpp +++ b/src/widgets/downloadlistwidget.cpp @@ -1,8 +1,16 @@ #include "downloadlistwidget.h" #include "ui_downloadlistwidget.h" -#include -#include +#include "widgets/common/downloaditem.h" +#include "backend/sparkapi.h" +#include "backend/downloadworker.h" +#include "utils/utils.h" +#include "application.h" +#include "mainwindow-dtk.h" + +#include +#include #include + DownloadListWidget::DownloadListWidget(QWidget *parent) : DBlurEffectWidget(parent), ui(new Ui::DownloadListWidget) { @@ -56,31 +64,27 @@ DownloadListWidget::~DownloadListWidget() { downloadController->disconnect(); downloadController->stopDownload(); - downloadController->deleteLater(); + // 这里没有释放 downloadController,使用懒汉式单例 } clearItem(); delete ui; } +bool DownloadListWidget::isDownloadInProcess() +{ + if (toDownload > 0) + { + return true; + } + return false; +} + void DownloadListWidget::clearItem() { - // QListWidgetItem *item = nullptr; - // while ((item = ui->listWidget->takeItem(0)) != nullptr) - // { - // QWidget *card = ui->listWidget->itemWidget(item); - // if (card) - // { - // card->deleteLater(); - // card = nullptr; - // } - // delete item; - // item = nullptr; - // } - - // ui->listWidget->vScrollBar->scrollTop(); ui->listWidget->clear(); } + DownloadItem* DownloadListWidget::addItem(QString name, QString fileName, QString pkgName, const QPixmap icon, QString downloadurl) { if (fileName.isEmpty()) @@ -89,6 +93,7 @@ DownloadItem* DownloadListWidget::addItem(QString name, QString fileName, QStrin } urList.append(downloadurl); allDownload += 1; + toDownload += 1; DownloadItem *di = new DownloadItem; dlist << downloadurl; downloaditemlist << di; @@ -127,13 +132,17 @@ void DownloadListWidget::startRequest(QUrl url, QString fileName) isdownload = true; downloaditemlist[allDownload - 1]->free = false; - if (downloadController) + // 使用懒汉式单例来存储downloadController + if (downloadController == nullptr) + { + downloadController = new DownloadController; // 并发下载,在第一次点击下载按钮的时候才会初始化 + } + else { downloadController->disconnect(); downloadController->stopDownload(); - downloadController->deleteLater(); } - downloadController = new DownloadController; // 并发下载,在点击下载按钮的时候才会初始化 + connect(downloadController, &DownloadController::downloadProcess, this, &DownloadListWidget::updateDataReadProgress); connect(downloadController, &DownloadController::downloadFinished, this, &DownloadListWidget::httpFinished); // connect(downloadController, &DownloadController::errorOccur, this, [=](QString msg){this->sendNotification(msg);}); @@ -141,30 +150,57 @@ void DownloadListWidget::startRequest(QUrl url, QString fileName) downloadController->startDownload(url.toString()); } +/*************************************************************** + * @brief 下载列表完成下载的回调函数 + * @param + * @note 如果正在安装,则在新开的线程空间中等待上一个安装完 + * @Sample usage: + **************************************************************/ void DownloadListWidget::httpFinished() // 完成下载 { isdownload = false; isBusy = false; - downloaditemlist[nowDownload - 1]->readyInstall(); - downloaditemlist[nowDownload - 1]->free = true; - emit downloadFinished(); - if (nowDownload < allDownload) + + QtConcurrent::run([=]() { - // 如果有排队则下载下一个 - qDebug() << "切换下一个下载..."; - nowDownload += 1; - while (downloaditemlist[nowDownload - 1]->close) + while (downloaditemlist[nowDownload - 1]->readyInstall() == -1) // 安装当前应用,堵塞安装,后面的下载suspend { - nowDownload += 1; - if (nowDownload >= allDownload) + continue; + } + toDownload -= 1; // 安装完以后减少待安装数目 + qDebug() << "Download: 还没有下载的数目:" << toDownload; + + if (toDownload == 0) + { + Application *app = qobject_cast(qApp); + MainWindow *mainWindow = app->mainWindow(); + if (mainWindow->isCloseWindowAnimation() == true) { - nowDownload = allDownload; - return; + qDebug() << "Download: 后台安装结束,退出程序"; + qApp->quit(); } } - QString fileName = downloaditemlist[nowDownload - 1]->getName(); - startRequest(urList.at(nowDownload - 1), fileName); - } + + downloaditemlist[nowDownload - 1]->free = true; + emit downloadFinished(); + if (nowDownload < allDownload) + { + // 如果有排队则下载下一个 + qDebug() << "Download: 切换下一个下载..."; + nowDownload += 1; + while (downloaditemlist[nowDownload - 1]->close) + { + nowDownload += 1; + if (nowDownload >= allDownload) + { + nowDownload = allDownload; + return; + } + } + QString fileName = downloaditemlist[nowDownload - 1]->getName(); + startRequest(urList.at(nowDownload - 1), fileName); + } + }); } void DownloadListWidget::updateDataReadProgress(QString speedInfo, qint64 bytesRead, qint64 totalBytes) @@ -195,21 +231,7 @@ void DownloadListWidget::m_move(int x, int y) move(x, y); return; } -bool DownloadListWidget::eventFilter(QObject *watched, QEvent *event) -{ - if (Q_NULLPTR == watched) - { - return false; - } - if (QEvent::ActivationChange == event->type()) - { - if (QApplication::activeWindow() != this) - { - this->close(); - } - } - return QWidget::eventFilter(watched, event); -} + void DownloadListWidget::mouseMoveEvent(QMouseEvent *event) { setGeometry(m_rect); diff --git a/src/widgets/downloadlistwidget.h b/src/widgets/downloadlistwidget.h index 82f7cf8..09517f5 100644 --- a/src/widgets/downloadlistwidget.h +++ b/src/widgets/downloadlistwidget.h @@ -1,20 +1,19 @@ #ifndef DOWNLOADLISTWIDGET_H #define DOWNLOADLISTWIDGET_H +#include + #include #include -#include -#include -#include -#include "widgets/common/downloaditem.h" -#include "backend/sparkapi.h" -#include "backend/downloadworker.h" -#include "utils/utils.h" -DWIDGET_USE_NAMESPACE + namespace Ui { class DownloadListWidget; } +DWIDGET_USE_NAMESPACE + +class DownloadItem; +class DownloadController; class DownloadListWidget : public DBlurEffectWidget { Q_OBJECT @@ -23,11 +22,17 @@ public: DownloadItem *addItem(QString name, QString fileName, QString pkgName, const QPixmap icon, QString downloadurl); int nowDownload = 0; int allDownload = 0; + int toDownload = 0; QList getDIList(); QList getUrlList(); void m_move(int x, int y); explicit DownloadListWidget(QWidget *parent = nullptr); - ~DownloadListWidget(); + ~DownloadListWidget() override; + + bool isDownloadInProcess(); + +protected: + void mouseMoveEvent(QMouseEvent *event) override; private: int isdownload = false; @@ -48,13 +53,13 @@ private: void clearItem(); QRect m_rect; Ui::DownloadListWidget *ui; -private slots: - bool eventFilter(QObject *, QEvent *); - void mouseMoveEvent(QMouseEvent *event); - void on_pushButton_clicked(); + signals: void downloadFinished(); void downloadProgress(int i); + +private slots: + void on_pushButton_clicked(); }; #endif // DOWNLOADLISTWIDGET_H diff --git a/tool/aptss b/tool/aptss index 9a4b257..46a1d57 100755 --- a/tool/aptss +++ b/tool/aptss @@ -8,23 +8,23 @@ mkdir -p /tmp/aptss-conf/ echo "从服务器获取配置和镜像列表..." echo "Getting server and mirror lists..." echo -curl --progress-bar -o /tmp/aptss-conf/apt-fast.conf "https://gitee.com/deepin-community-store/repo_auto_update_script/raw/master/mirror-list-for-apt-fast/apt-fast.conf" +curl --progress-bar -o /tmp/aptss-conf/apt-fast.conf "https://d.store.deepinos.org.cn/apt-fast.conf" chmod -R 755 /tmp/aptss-conf fi -if [ ! -e "/var/lib/apt/lists/d.store.deepinos.org.cn_Packages" ] && [ ! -e "/var/lib/apt/lists/d.store.deepinos.org.cn_store_Packages" ];then +if [ ! -e "/var/lib/apt/lists/d.spark-app.store_store_Packages" ] && [ ! -e "/var/lib/apt/lists/d.store.deepinos.org.cn_store_Packages" ] && [ ! -e "/var/lib/apt/lists/mirrors.sdu.edu.cn_spark-store-repository_store_Packages" ];then echo "接收星火仓库软件信息中..." mkdir -p /tmp/aptss-conf/ echo "从服务器获取配置和镜像列表..." echo "Getting server and mirror lists..." echo -curl --silent -o /tmp/aptss-conf/apt-fast.conf "https://gitee.com/deepin-community-store/repo_auto_update_script/raw/master/mirror-list-for-apt-fast/apt-fast.conf" +curl --silent -o /tmp/aptss-conf/apt-fast.conf "https://d.store.deepinos.org.cn/apt-fast.conf" chmod -R 755 /tmp/aptss-conf -sudo curl --silent -o /opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list "https://gitee.com/deepin-community-store/repo_auto_update_script/raw/master/mirror-list-for-apt-fast/sources.list.d/sparkstore.list" +sudo curl --silent -o /opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list "https://d.store.deepinos.org.cn/sparkstore.list" sudo bwrap --dev-bind / / --bind '/opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list' /etc/apt/sources.list.d/sparkstore.list apt update -o Dir::Etc::sourcelist="sources.list.d/sparkstore.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" #只更新星火源 @@ -69,23 +69,23 @@ mkdir -p /tmp/aptss-conf/ echo "从服务器获取配置和镜像列表..." echo "Getting server and mirror lists..." echo -curl --silent -o /tmp/aptss-conf/apt-fast.conf "https://gitee.com/deepin-community-store/repo_auto_update_script/raw/master/mirror-list-for-apt-fast/apt-fast.conf" +curl --silent -o /tmp/aptss-conf/apt-fast.conf "https://d.store.deepinos.org.cn/apt-fast.conf" chmod -R 755 /tmp/aptss-conf -sudo curl --silent -o /opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list "https://gitee.com/deepin-community-store/repo_auto_update_script/raw/master/mirror-list-for-apt-fast/sources.list.d/sparkstore.list" +sudo curl --silent -o /opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list "https://d.store.deepinos.org.cn/sparkstore.list" sudo bwrap --dev-bind / / --bind '/opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list' /etc/apt/sources.list.d/sparkstore.list apt update -o Dir::Etc::sourcelist="sources.list.d/sparkstore.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0" #只更新星火源 elif [ "$1" = "update" ];then -sudo curl --progress-bar -o /opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list "https://gitee.com/deepin-community-store/repo_auto_update_script/raw/master/mirror-list-for-apt-fast/sources.list.d/sparkstore.list" +sudo curl --progress-bar -o /opt/durapps/spark-store/bin/apt-fast-conf/sources.list.d/sparkstore.list "https://d.store.deepinos.org.cn/sparkstore.list" mkdir -p /tmp/aptss-conf/ echo "从服务器获取配置和镜像列表..." echo "Getting server and mirror lists..." echo -curl --progress-bar -o /tmp/aptss-conf/apt-fast.conf "https://gitee.com/deepin-community-store/repo_auto_update_script/raw/master/mirror-list-for-apt-fast/apt-fast.conf" +curl --progress-bar -o /tmp/aptss-conf/apt-fast.conf "https://d.store.deepinos.org.cn/apt-fast.conf" chmod -R 755 /tmp/aptss-conf ### 额外一份拿来给aptss自动补全用 bwrap --dev-bind / / \ diff --git a/tool/ssinstall b/tool/ssinstall index 18a925f..e422f60 100755 --- a/tool/ssinstall +++ b/tool/ssinstall @@ -54,19 +54,22 @@ fi DEBPATH=`realpath $1` -if [ ! -e "/var/lib/apt/lists/d.store.deepinos.org.cn_Packages" ] && [ ! -e "/var/lib/apt/lists/d.store.deepinos.org.cn_store_Packages" ];then +if [ ! -e "/var/lib/apt/lists/d.store.deepinos.org.cn_Packages" ] && [ ! -e "/var/lib/apt/lists/d.store.deepinos.org.cn_store_Packages" ] && [ ! -e "/var/lib/apt/lists/mirrors.sdu.edu.cn_spark-store-repository_store_Packages" ];then echo "接收星火仓库软件信息中..." aptss ssupdate fi ### 选择包信息位置 -if [ -e "/var/lib/apt/lists/d.store.deepinos.org.cn_store_Packages" ];then -PACKAGES_DATA_PATH="/var/lib/apt/lists/d.store.deepinos.org.cn_store_Packages" -echo "星火仓库的Packages位置为 $PACKAGES_DATA_PATH,是单目录仓库配置" -else +if [ -e "/var/lib/apt/lists/d.spark-app.store_store_Packages" ];then +PACKAGES_DATA_PATH="/var/lib/apt/lists/d.spark-app.store_store_Packages" +echo "星火仓库的Packages位置为 $PACKAGES_DATA_PATH,是星火域名单目录仓库配置" +elif [ -e "/var/lib/apt/lists/d.store.deepinos.org.cn_Packages" ];then PACKAGES_DATA_PATH="/var/lib/apt/lists/d.store.deepinos.org.cn_Packages" echo "星火仓库的Packages位置为 $PACKAGES_DATA_PATH,是根目录仓库配置" +else +PACKAGES_DATA_PATH="/var/lib/apt/lists/mirrors.sdu.edu.cn_spark-store-repository_store_Packages" +echo "星火仓库的Packages位置为 $PACKAGES_DATA_PATH,是SDU镜像仓库配置" fi diff --git a/translations/spark-store_en.ts b/translations/spark-store_en.ts index d0b7e84..d70c3b5 100644 --- a/translations/spark-store_en.ts +++ b/translations/spark-store_en.ts @@ -10,9 +10,9 @@ - - - + + + Download @@ -175,51 +175,51 @@ - + Click Open - + Developer Mode Disabled - - - + + + Reinstall - + Upgrade - - + + Install - + Installing - - + + Spark Store - + Uninstall succeeded - + The URL has been copied to the clipboard @@ -240,12 +240,12 @@ DAboutDialog - + Version: %1 - + %1 is released under %2 @@ -299,59 +299,59 @@ - - - + + + Spark Store - - + + Installing - + Installation complete. - - + + Finish - + Retry - + Error happened in dpkg progress , you can try it again. - - + + Error happened in dpkg progress , you can try it again - + dpkg progress had been aborted,you can retry installation. - - + + dpkg progress had been aborted,you can retry installation - - + + Download canceled @@ -452,33 +452,33 @@ - + Submit App - + Submit App with client(Recommanded) - + Settings - + APP Upgrade and Install Settings - - + + Spark Store - + Search or enter spk:// @@ -486,29 +486,29 @@ QObject - - - + + + Spark Store - + <span style=' font-size:10pt;font-weight:60;'>An appstore powered by community</span><br/><a href='https://www.spark-app.store/'>https://www.spark-app.store</a><br/><span style=' font-size:12pt;'>Spark developers</span> - + Spark Project - + Download list - + Show MainWindow @@ -619,12 +619,12 @@ TitleBarMenu - + About - + Exit diff --git a/translations/spark-store_fr.ts b/translations/spark-store_fr.ts index 3e296e2..356294c 100644 --- a/translations/spark-store_fr.ts +++ b/translations/spark-store_fr.ts @@ -10,9 +10,9 @@ - - - + + + Download @@ -175,51 +175,51 @@ - + Click Open - + Developer Mode Disabled - - - + + + Reinstall - + Upgrade - - + + Install - + Installing - - + + Spark Store - + Uninstall succeeded - + The URL has been copied to the clipboard @@ -240,12 +240,12 @@ DAboutDialog - + Version: %1 - + %1 is released under %2 @@ -299,59 +299,59 @@ - - - + + + Spark Store - - + + Installing - + Installation complete. - - + + Finish - + Retry - + Error happened in dpkg progress , you can try it again. - - + + Error happened in dpkg progress , you can try it again - + dpkg progress had been aborted,you can retry installation. - - + + dpkg progress had been aborted,you can retry installation - - + + Download canceled @@ -452,33 +452,33 @@ - + Submit App - + Submit App with client(Recommanded) - + Settings - + APP Upgrade and Install Settings - - + + Spark Store - + Search or enter spk:// @@ -486,29 +486,29 @@ QObject - - - + + + Spark Store - + <span style=' font-size:10pt;font-weight:60;'>An appstore powered by community</span><br/><a href='https://www.spark-app.store/'>https://www.spark-app.store</a><br/><span style=' font-size:12pt;'>Spark developers</span> - + Spark Project - + Download list - + Show MainWindow @@ -619,12 +619,12 @@ TitleBarMenu - + About - + Exit diff --git a/translations/spark-store_zh_CN.ts b/translations/spark-store_zh_CN.ts index 66b874b..491792c 100644 --- a/translations/spark-store_zh_CN.ts +++ b/translations/spark-store_zh_CN.ts @@ -10,9 +10,9 @@ - - - + + + Download 下载 @@ -175,51 +175,51 @@ 软件官网 - + Click Open 点击跳转 - + Developer Mode Disabled 开发者模式未开启 - - - + + + Reinstall 重新安装 - + Upgrade 升级 - - + + Install 安装 - + Installing 正在安装 - - + + Spark Store 星火应用商店 - + Uninstall succeeded 卸载成功 - + The URL has been copied to the clipboard 链接已复制到剪贴板 @@ -240,12 +240,12 @@ DAboutDialog - + Version: %1 版本:%1 - + %1 is released under %2 %1遵循%2协议发布 @@ -299,59 +299,59 @@ 下载完成. - - - + + + Spark Store 星火应用商店 - - + + Installing 正在安装 - + Installation complete. 安装完成. - - + + Finish 完成 - + Retry 重试 - + Error happened in dpkg progress , you can try it again. 安装被中止,可重新安装。 - - + + Error happened in dpkg progress , you can try it again dpkg出现错误,可重新安装 - + dpkg progress had been aborted,you can retry installation. dpkg进程被中断,您可重试安装。 - - + + dpkg progress had been aborted,you can retry installation 安装被中止,可重新安装 - - + + Download canceled 下载已取消 @@ -452,33 +452,33 @@ 更新 - + Submit App 投递应用 - + Submit App with client(Recommanded) 使用本地投稿器投递应用(推荐) - + Settings 设置 - + APP Upgrade and Install Settings 应用更新和安装设置 - - + + Spark Store 星火应用商店 - + Search or enter spk:// 搜索或打开链接 @@ -486,29 +486,29 @@ QObject - - - + + + Spark Store 星火应用商店 - + <span style=' font-size:10pt;font-weight:60;'>An appstore powered by community</span><br/><a href='https://www.spark-app.store/'>https://www.spark-app.store</a><br/><span style=' font-size:12pt;'>Spark developers</span> <span style=' font-size:10pt;font-weight:60;'>一款由社区提供的应用商店</span><br/><a href='https://www.spark-app.store/'>https://www.spark-app.store</a><br/><span style=' font-size:12pt;'>星火计划开发者</span> - + Spark Project 星火计划 - + Download list 下载列表 - + Show MainWindow 显示主窗口 @@ -619,12 +619,12 @@ TitleBarMenu - + About 关于 - + Exit 退出 diff --git a/translations/spark-store_zh_TW.ts b/translations/spark-store_zh_TW.ts index ac5dc06..64bc98e 100644 --- a/translations/spark-store_zh_TW.ts +++ b/translations/spark-store_zh_TW.ts @@ -10,9 +10,9 @@ - - - + + + Download 下载 @@ -175,51 +175,51 @@ 软件官网 - + Click Open 点击跳转 - + Developer Mode Disabled 开发者模式未开启 - - - + + + Reinstall 重新安裝 - + Upgrade 升级 - - + + Install 安装 - + Installing 正在安装 - - + + Spark Store 星火应用商店 - + Uninstall succeeded 卸载成功 - + The URL has been copied to the clipboard 链接已复制到剪贴板 @@ -240,12 +240,12 @@ DAboutDialog - + Version: %1 版本:%1 - + %1 is released under %2 %1遵循%2协议发布 @@ -299,59 +299,59 @@ 下載完成. - - - + + + Spark Store 星火应用商店 - - + + Installing 正在安裝 - + Installation complete. 安裝完成. - - + + Finish 完成 - + Retry 重试 - + Error happened in dpkg progress , you can try it again. 安装被中止,可重新安装。 - - + + Error happened in dpkg progress , you can try it again dpkg出现错误,可重新安装 - + dpkg progress had been aborted,you can retry installation. dpkg进程被中断,您可重试安装。 - - + + dpkg progress had been aborted,you can retry installation 安装被中止,可重新安装 - - + + Download canceled 下载已取消 @@ -452,33 +452,33 @@ 軟體更新 - + Submit App 上傳軟體 - + Submit App with client(Recommanded) 從客戶端上傳軟體(推薦的) - + Settings 設定 - + APP Upgrade and Install Settings 軟體升級 和 安裝設定 - - + + Spark Store 星火应用商店 - + Search or enter spk:// 搜索或打开链接 @@ -486,29 +486,29 @@ QObject - - - + + + Spark Store 星火应用商店 - + <span style=' font-size:10pt;font-weight:60;'>An appstore powered by community</span><br/><a href='https://www.spark-app.store/'>https://www.spark-app.store</a><br/><span style=' font-size:12pt;'>Spark developers</span> <span style=' font-size:10pt;font-weight:60;'>一款由社区提供的应用商店</span><br/><a href='https://www.spark-app.store/'>https://www.spark-app.store</a><br/><span style=' font-size:12pt;'>星火计划开发者</span> - + Spark Project 星火计划 - + Download list 下载列表 - + Show MainWindow 显示主窗口 @@ -619,12 +619,12 @@ TitleBarMenu - + About 关于 - + Exit 退出