├── .dockerignore ├── debian ├── compat ├── source │ ├── format │ └── local-options ├── rules ├── gbp.conf ├── pardus-store.postinst ├── control ├── copyright └── changelog ├── Pardus-Regular.otf ├── screenshots ├── ps-1.png ├── ps-2.png ├── ps-3.png ├── ps-4.png ├── ps-5.png ├── ps-6.png └── ps-7.png ├── translations └── pardus-store_tr.qm ├── file.qrc ├── translations.qrc ├── Dockerfile ├── .gitignore ├── src ├── condition.h ├── filehandler.h ├── singleton.h ├── dpkg-progress.h ├── iconprovider.h ├── packagehandler.h ├── namfactory.h ├── application.h ├── filehandler.cpp ├── applicationlistmodel.h ├── main.cpp ├── singleton.cpp ├── networkhandler.h ├── applicationdetail.h ├── dpkg-progress.cpp ├── application.cpp ├── applicationlistmodel.cpp ├── packagehandler.cpp ├── applicationdetail.cpp ├── helper.h └── helper.cpp ├── qtquickcontrols2.conf ├── ui ├── Seperator.qml ├── FadeAnimation.qml ├── BottomDock.qml ├── ProgressBarCircle.qml ├── ApplicationList.qml ├── InfoDialog.qml ├── ConfirmationDialog.qml ├── SplashScreen.qml ├── QueueDialog.qml ├── SearchBar.qml ├── SurveyDetail.qml └── NavigationBar.qml ├── .travis.yml ├── pardus-store.desktop ├── qml.qrc ├── README.md ├── tr.org.pardus.pkexec.pardus-store.policy ├── images.qrc ├── pardus-store.pro └── images ├── home.svg ├── home-dark.svg ├── star-dark.svg ├── star.svg ├── all.svg ├── email.svg ├── email-dark.svg ├── categories.svg ├── categories-dark.svg ├── website.svg ├── website-dark.svg ├── settings.svg ├── settings-dark.svg ├── back.svg ├── front.svg ├── download.svg ├── download-dark.svg ├── rating-stars.svg ├── rating-stars-light.svg ├── search.svg ├── search-dark.svg ├── clear.svg └── clear-dark.svg /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /debian/source/local-options: -------------------------------------------------------------------------------- 1 | extend-diff-ignore = ".drone.yml" 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | export QT_SELECT := qt5 3 | 4 | %: 5 | dh $@ 6 | -------------------------------------------------------------------------------- /Pardus-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/Pardus-Regular.otf -------------------------------------------------------------------------------- /debian/gbp.conf: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | 3 | upstream-branch = master 4 | upstream-tag = %(version)s 5 | -------------------------------------------------------------------------------- /debian/pardus-store.postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | dpkg --add-architecture i386 6 | -------------------------------------------------------------------------------- /screenshots/ps-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/screenshots/ps-1.png -------------------------------------------------------------------------------- /screenshots/ps-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/screenshots/ps-2.png -------------------------------------------------------------------------------- /screenshots/ps-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/screenshots/ps-3.png -------------------------------------------------------------------------------- /screenshots/ps-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/screenshots/ps-4.png -------------------------------------------------------------------------------- /screenshots/ps-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/screenshots/ps-5.png -------------------------------------------------------------------------------- /screenshots/ps-6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/screenshots/ps-6.png -------------------------------------------------------------------------------- /screenshots/ps-7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/screenshots/ps-7.png -------------------------------------------------------------------------------- /translations/pardus-store_tr.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yunusem/pardus-store/HEAD/translations/pardus-store_tr.qm -------------------------------------------------------------------------------- /file.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | qtquickcontrols2.conf 4 | Pardus-Regular.otf 5 | 6 | 7 | -------------------------------------------------------------------------------- /translations.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | translations/pardus-store_tr.qm 4 | translations/pardus-store_tr.ts 5 | 6 | 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch-slim 2 | MAINTAINER Yunusemre Şentürk 3 | 4 | RUN apt-get update && apt-get install \ 5 | build-essential equivs devscripts --no-install-recommends -y 6 | 7 | COPY . /pardus-store 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # git ls-files --others --exclude-from=.git/info/exclude 2 | # Lines that start with '#' are comments. 3 | # For a project mostly in C, the following would be a good set of 4 | # exclude patterns (uncomment them if you want to use them): 5 | *.[oa] 6 | 7 | # editor backups 8 | *~ 9 | *.sw? 10 | 11 | # qt specific stuff 12 | moc_*.cpp 13 | qrc_*.cpp 14 | .qmake.stash 15 | 16 | *.pro.user 17 | -------------------------------------------------------------------------------- /src/condition.h: -------------------------------------------------------------------------------- 1 | #ifndef CONDITION_H 2 | #define CONDITION_H 3 | 4 | #include 5 | 6 | class Condition : public QObject 7 | { 8 | Q_OBJECT 9 | public: 10 | enum State { 11 | Idle, 12 | Installed, 13 | Removed, 14 | Downloading, 15 | Installing, 16 | Removing 17 | }; 18 | Q_ENUM(State) 19 | }; 20 | 21 | #endif // CONDITION_H 22 | -------------------------------------------------------------------------------- /qtquickcontrols2.conf: -------------------------------------------------------------------------------- 1 | ; This file can be edited to change the style of the application 2 | ; See Styling Qt Quick Controls 2 in the documentation for details: 3 | ; http://doc.qt.io/qt-5/qtquickcontrols2-styles.html 4 | 5 | [Controls] 6 | Style=Material 7 | 8 | [Universal] 9 | Theme=Light 10 | ;Accent=Steel 11 | 12 | [Material] 13 | Theme=Dark 14 | Foreground=#E4E4E4 15 | Background=#2B2B2B 16 | Accent=#FFCB08 17 | Primary=#464646 18 | -------------------------------------------------------------------------------- /src/filehandler.h: -------------------------------------------------------------------------------- 1 | #ifndef FILEHANDLER_H 2 | #define FILEHANDLER_H 3 | 4 | #include 5 | 6 | class FileHandler : public QObject 7 | { 8 | Q_OBJECT 9 | public: 10 | explicit FileHandler(QObject *parent = 0); 11 | void correctSources(); 12 | 13 | signals: 14 | void correctingSourcesFinished(); 15 | void correctingSourcesFinishedWithError(const QString &err); 16 | 17 | }; 18 | 19 | #endif // FILEHANDLER_H 20 | -------------------------------------------------------------------------------- /ui/Seperator.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | Rectangle { 4 | id: seperator 5 | color: "transparent" 6 | property alias lineColor: line.color 7 | anchors { 8 | left: parent.left 9 | right: parent.right 10 | } 11 | 12 | Rectangle { 13 | id: line 14 | color: "#2B2B2B" 15 | width: parent.width 16 | height: 1 17 | radius: height / 2 18 | anchors.verticalCenter: parent.verticalCenter 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | 3 | language: cpp 4 | 5 | services: 6 | - docker 7 | 8 | before_install: 9 | - docker build -t pardus/pardus-store . 10 | - docker run -d --name build pardus/pardus-store tail -f /dev/null 11 | 12 | install: 13 | - docker exec build /bin/sh -c 'cd /pardus-store; mk-build-deps -i -r -t "apt-get -o Debug::pkgProblemResolver=yes --no-install-recommends -y"' 14 | 15 | script: 16 | - docker exec build /bin/sh -c 'cd /pardus-store; dpkg-buildpackage -b -uc' 17 | -------------------------------------------------------------------------------- /pardus-store.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Name=Pardus Store 4 | Name[tr]=Pardus Mağaza 5 | Type=Application 6 | Comment=Simple Qt based application store 7 | Comment[tr]=Basit Qt tabanlı uygulama mağazası 8 | Terminal=false 9 | Exec=pkexec /usr/bin/pardus-store 10 | Icon=/usr/share/pardus/pardus-store/icon.svg 11 | MimeType=application/x-iso-image; 12 | Categories=Qt;Utility; 13 | Keywords=usb;disk;writer;burner; 14 | GenericName=Application Store 15 | GenericName[tr]=Uygulama Mağazası 16 | -------------------------------------------------------------------------------- /ui/FadeAnimation.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | 3 | SequentialAnimation { 4 | id: fade 5 | property QtObject target 6 | property string child: "opacity" 7 | property int duration 8 | NumberAnimation { 9 | id: outAnimation 10 | target: fade.target 11 | property: fade.child 12 | duration: fade.duration / 2 13 | to: 0.0 14 | } 15 | PropertyAction { } 16 | NumberAnimation { 17 | id: inAnimation 18 | target: fade.target 19 | property: fade.child 20 | duration: fade.duration / 2 21 | to: 1.0 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/singleton.h: -------------------------------------------------------------------------------- 1 | #ifndef SINGLETON_H 2 | #define SINGLETON_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Singleton 9 | { 10 | public: 11 | Singleton(const QString &key); 12 | ~Singleton(); 13 | bool isAnotherRunning(); 14 | bool tryToRun(); 15 | void release(); 16 | 17 | private: 18 | const QString m_key; 19 | const QString m_memoryLockKey; 20 | const QString m_sharedMemoryKey; 21 | 22 | QSharedMemory m_sharedMemory; 23 | QSystemSemaphore m_systemSemaphore; 24 | 25 | Q_DISABLE_COPY( Singleton ) 26 | 27 | }; 28 | 29 | #endif // SINGLETON_H 30 | -------------------------------------------------------------------------------- /ui/BottomDock.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Window 2.0 4 | import QtQuick.Controls.Material 2.0 5 | 6 | Rectangle { 7 | width: parent.width * 20 / 21 8 | height: parent.height / 15 9 | z: 89 10 | anchors { 11 | bottom: parent.bottom 12 | right: parent.right 13 | } 14 | 15 | //Material.elevation: 3 16 | color: "transparent" 17 | property alias pageIndicator: indicator 18 | 19 | 20 | 21 | 22 | PageIndicator { 23 | id: indicator 24 | interactive: false 25 | visible: stackView.depth > 1 26 | count: stackView.depth 27 | currentIndex: stackView.depth -1 28 | anchors.top: parent.top 29 | anchors.horizontalCenter: parent.horizontalCenter 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | ui/main.qml 4 | ui/NavigationBar.qml 5 | ui/ApplicationDelegate.qml 6 | ui/SearchBar.qml 7 | ui/Home.qml 8 | ui/ApplicationDetail.qml 9 | ui/BottomDock.qml 10 | ui/SplashScreen.qml 11 | ui/QueueDialog.qml 12 | ui/ConfirmationDialog.qml 13 | ui/InfoDialog.qml 14 | ui/Settings.qml 15 | ui/ProgressBarCircle.qml 16 | ui/ApplicationList.qml 17 | ui/FadeAnimation.qml 18 | ui/Seperator.qml 19 | ui/SurveyDetail.qml 20 | 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/yunusem/pardus-store.svg?branch=master)](https://travis-ci.org/yunusem/pardus-store) 2 | 3 | # Pardus Store 4 | 5 | Pardus Store is an application store front-end for debian based operating systems. 6 | 7 | It is currently a work in progress. Maintenance is done by [Pardus](https://pardus.org.tr) team. 8 | 9 | Currently the server side of the store is on a test environment and can be updated to a dedicated server in the future. 10 | 11 | You can join the discussion on [Pardus Forums](https://forum.pardus.org.tr/t/pardus-magaza-beta-surumu-yayinlandi/4768/426). 12 | 13 | 14 | ## Screen Shots 15 | 16 | ### On Linux (Pardus 17.4 GNU/Linux) 17 | 18 | ![p1](screenshots/ps-1.png) 19 | 20 | ![p2](screenshots/ps-2.png) 21 | 22 | ![p3](screenshots/ps-3.png) 23 | 24 | ![p4](screenshots/ps-4.png) 25 | 26 | ![p5](screenshots/ps-5.png) 27 | 28 | ![p6](screenshots/ps-6.png) 29 | 30 | ![p7](screenshots/ps-7.png) 31 | -------------------------------------------------------------------------------- /tr.org.pardus.pkexec.pardus-store.policy: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Pardus Developers 8 | http://www.pardus.org.tr/ 9 | 10 | 11 | Authentication is required to run Pardus Store as root 12 | Pardus Mağazayı çalıştırmak için yetkilendirme gerekli 13 | pardus-store 14 | 15 | auth_admin 16 | auth_admin 17 | auth_admin 18 | 19 | /usr/bin/pardus-store 20 | true 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/dpkg-progress.h: -------------------------------------------------------------------------------- 1 | #ifndef DPKG_PROGRESS_H_ 2 | #define DPKG_PROGRESS_H_ 3 | 4 | #include 5 | 6 | class QString; 7 | class QSocketNotifier; 8 | 9 | class DpkgProgress : public QObject 10 | { 11 | Q_OBJECT 12 | public: 13 | DpkgProgress(QObject *parent = nullptr); 14 | virtual ~DpkgProgress(); 15 | 16 | int statusFd(); 17 | 18 | signals: 19 | void dpkgProgress(const QString &status, const QString &pkg, 20 | int value, const QString &desc); 21 | 22 | private slots: 23 | void onReadable(); 24 | 25 | private: 26 | size_t avail() const; 27 | void processLine(const char *s); 28 | void notifyProgress(QStringList line, int percent = -1); 29 | 30 | QStringList m_line; 31 | QSocketNotifier *m_notifier; 32 | 33 | static const unsigned int BUF_SIZE = 128; 34 | char buf[BUF_SIZE], *pos; 35 | int pipefd, wrend; 36 | }; 37 | 38 | inline size_t DpkgProgress::avail() const 39 | { 40 | return &buf[BUF_SIZE] - pos; 41 | } 42 | 43 | #endif /* end of include guard: DPKG_PROGRESS_H_ */ 44 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: pardus-store 2 | Section: utils 3 | Priority: optional 4 | Maintainer: Yunusemre Şentürk 5 | Build-Depends: debhelper (>= 9), 6 | libc6, 7 | libgcc1, 8 | libgcc-6-dev, 9 | libgl1-mesa-glx | libgl1, 10 | libqt5core5a, 11 | libqt5gui5, 12 | libqt5network5, 13 | libqt5qml5, 14 | libqt5quick5, 15 | libqt5svg5-dev, 16 | libqt5widgets5, 17 | libstdc++6, 18 | qtdeclarative5-dev 19 | Standards-Version: 3.9.8 20 | Homepage: http://pardus.org.tr 21 | 22 | Package: pardus-store 23 | Architecture: amd64 24 | Depends: ${shlibs:Depends}, ${misc:Depends}, 25 | apt-transport-https, 26 | libqt5svg5, 27 | libnotify-bin, 28 | policykit-1, 29 | qml-module-qtquick-controls2, 30 | qml-module-qtquick2, 31 | qml-module-qtgraphicaleffects, 32 | qml-module-qtquick-controls, 33 | qml-module-qtquick-templates2 34 | Recommends: pardus-icon-theme 35 | Description: Pardus Application Store 36 | Qt based nice looking simple to use responsive application store. 37 | -------------------------------------------------------------------------------- /src/iconprovider.h: -------------------------------------------------------------------------------- 1 | #ifndef ICONPROVIDER_H 2 | #define ICONPROVIDER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define default_icon_theme "pardus" 9 | 10 | class IconProvider : public QQuickImageProvider 11 | { 12 | public: 13 | IconProvider() : QQuickImageProvider(QQuickImageProvider::Pixmap) 14 | { 15 | 16 | } 17 | virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) 18 | { 19 | if (size) { 20 | *size = QSize(64, 64); 21 | } 22 | const QIcon defaultIcon = QIcon::fromTheme("image-missing",QIcon(id)); 23 | defaultIcon.setThemeName(default_icon_theme); 24 | QIcon icon = QIcon::fromTheme(id, defaultIcon); 25 | icon.setThemeName(default_icon_theme); 26 | 27 | QPixmap pixmap = icon.pixmap(icon.actualSize(QSize(requestedSize.width() > 0 ? requestedSize.width() : 64, 28 | requestedSize.height() > 0 ? requestedSize.height() : 64))); 29 | 30 | 31 | return pixmap; 32 | } 33 | 34 | }; 35 | 36 | #endif // ICONPROVIDER_H 37 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: pardus-store 3 | Source: https://github.com/yunusem/pardus-store 4 | 5 | 6 | 7 | Files: * 8 | Copyright: 2018 Yunusemre Senturk 9 | License: GPL-3.0+ 10 | 11 | License: GPL-3.0+ 12 | This program is free software: you can redistribute it and/or modify 13 | it under the terms of the GNU General Public License as published by 14 | the Free Software Foundation, either version 3 of the License, or 15 | (at your option) any later version. 16 | . 17 | This package is distributed in the hope that it will be useful, 18 | but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | GNU General Public License for more details. 21 | . 22 | You should have received a copy of the GNU General Public License 23 | along with this program. If not, see . 24 | . 25 | On Debian systems, the complete text of the GNU General 26 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 27 | 28 | 29 | -------------------------------------------------------------------------------- /images.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/home.svg 4 | images/all.svg 5 | images/settings.svg 6 | images/star.svg 7 | images/search.svg 8 | images/icon.svg 9 | images/back.svg 10 | images/front.svg 11 | images/categories.svg 12 | images/rating-stars.svg 13 | images/email.svg 14 | images/website.svg 15 | images/download.svg 16 | images/settings-dark.svg 17 | images/categories-dark.svg 18 | images/home-dark.svg 19 | images/search-dark.svg 20 | images/download-dark.svg 21 | images/star-dark.svg 22 | images/rating-stars-light.svg 23 | images/clear-dark.svg 24 | images/clear.svg 25 | images/website-dark.svg 26 | images/email-dark.svg 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/packagehandler.h: -------------------------------------------------------------------------------- 1 | #ifndef PACKAGEHANDLER_H 2 | #define PACKAGEHANDLER_H 3 | 4 | #include 5 | #include 6 | class QProcess; 7 | class QByteArray; 8 | class DpkgProgress; 9 | 10 | class PackageHandler : public QObject 11 | { 12 | Q_OBJECT 13 | public: 14 | explicit PackageHandler(QObject *parent = 0); 15 | ~PackageHandler(); 16 | private: 17 | QProcess *p; 18 | DpkgProgress *dpkg; 19 | int m_percent; 20 | QString m_status; 21 | 22 | signals: 23 | void finished(int code); 24 | void dpkgProgressStatus(const QString &status, const QString &pkg, int value, const QString &desc); 25 | 26 | public slots: 27 | void updateCache(); 28 | void install(const QString &pkg); 29 | void remove(const QString &pkg); 30 | bool terminate(); 31 | void onFinished(int code); 32 | QString getPolicy(const QString &pkg) const; 33 | QString getShow(const QString &pkg) const; 34 | QString getSearch(const QString &pkg) const; 35 | QByteArray getError(); 36 | QByteArray getOutput(); 37 | 38 | private slots: 39 | void onDpkgProgress(const QString &status, const QString &pkg, 40 | int value, const QString &desc); 41 | 42 | }; 43 | 44 | #endif // PACKAGEHANDLER_H 45 | -------------------------------------------------------------------------------- /pardus-store.pro: -------------------------------------------------------------------------------- 1 | QT += qml quick widgets svg network 2 | 3 | CONFIG += c++11 4 | 5 | SOURCES += src/main.cpp \ 6 | src/helper.cpp \ 7 | src/filehandler.cpp \ 8 | src/packagehandler.cpp \ 9 | src/applicationlistmodel.cpp \ 10 | src/networkhandler.cpp \ 11 | src/applicationdetail.cpp \ 12 | src/singleton.cpp \ 13 | src/dpkg-progress.cpp \ 14 | src/application.cpp 15 | 16 | HEADERS += \ 17 | src/helper.h \ 18 | src/filehandler.h \ 19 | src/packagehandler.h \ 20 | src/iconprovider.h \ 21 | src/applicationlistmodel.h \ 22 | src/networkhandler.h \ 23 | src/applicationdetail.h \ 24 | src/singleton.h \ 25 | src/dpkg-progress.h \ 26 | src/application.h \ 27 | src/namfactory.h \ 28 | src/condition.h 29 | 30 | TARGET = pardus-store 31 | 32 | RESOURCES += qml.qrc file.qrc \ 33 | images.qrc \ 34 | translations.qrc 35 | 36 | DEFINES += QT_DEPRECATED_WARNINGS 37 | 38 | target.path = /usr/bin 39 | 40 | desktop_file.files = pardus-store.desktop 41 | desktop_file.path = /usr/share/applications/ 42 | 43 | icon.files = images/icon.svg 44 | icon.commands = mkdir -p /usr/share/pardus/pardus-store 45 | icon.path = /usr/share/pardus/pardus-store 46 | 47 | policy.files = tr.org.pardus.pkexec.pardus-store.policy 48 | policy.commands = mkdir -p /usr/share/polkit-1/actions 49 | policy.path = /usr/share/polkit-1/actions 50 | 51 | INSTALLS += target desktop_file icon policy 52 | 53 | #LIBS += -lapt-pkg 54 | 55 | -------------------------------------------------------------------------------- /src/namfactory.h: -------------------------------------------------------------------------------- 1 | #ifndef NAMFACTORY_H 2 | #define NAMFACTORY_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define CACHE_PATH "/.cache/pardus-store/" 14 | 15 | class StoreNetworkAccessManager : public QNetworkAccessManager 16 | { 17 | public: 18 | StoreNetworkAccessManager(QObject *parent) : QNetworkAccessManager(parent) { } 19 | 20 | protected: 21 | QNetworkReply *createRequest(Operation operation, const QNetworkRequest &request, QIODevice *outgoingData = nullptr) override 22 | { 23 | QNetworkRequest cacheRequest(request); 24 | cacheRequest.setAttribute(QNetworkRequest::CacheLoadControlAttribute, 25 | (networkAccessible() == QNetworkAccessManager::Accessible) ? QNetworkRequest::PreferCache : QNetworkRequest::AlwaysCache); 26 | return QNetworkAccessManager::createRequest(operation, cacheRequest, outgoingData); 27 | } 28 | }; 29 | 30 | class NamFactory : public QQmlNetworkAccessManagerFactory 31 | { 32 | public: 33 | QNetworkAccessManager *create(QObject *parent) override; 34 | 35 | }; 36 | 37 | 38 | QNetworkAccessManager *NamFactory::create(QObject *parent) 39 | { 40 | QNetworkAccessManager *nam = new StoreNetworkAccessManager(parent); 41 | QNetworkDiskCache *cache = new QNetworkDiskCache(nam); 42 | cache->setCacheDirectory(QDir::homePath().append(QString(CACHE_PATH))); 43 | nam->setCache(cache); 44 | return nam; 45 | } 46 | 47 | #endif // NAMFACTORY_H 48 | -------------------------------------------------------------------------------- /src/application.h: -------------------------------------------------------------------------------- 1 | #ifndef APPLICATION_H 2 | #define APPLICATION_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Application 9 | { 10 | public: 11 | Application(const QString &name); 12 | 13 | QString name() const; 14 | QString version() const; 15 | unsigned int downloadcount(); 16 | QString downloadsize() const; 17 | QString category() const; 18 | QString categoryLocal() const; 19 | QString prettyname() const; 20 | QString exec() const; 21 | QString state() const; 22 | QString search() const; 23 | double rating() const; 24 | bool installed() const; 25 | bool inqueue() const; 26 | bool nonfree() const; 27 | 28 | void setVersion(const QString &version); 29 | void setDownloadcount(const unsigned int &downloadcount); 30 | void setDownloadsize(const QString &downloadsize); 31 | void setCategory(const QHash &category); 32 | void setPrettyname (const QHash &prettyname); 33 | void setExec(const QString &exec); 34 | void setState(const QString &state); 35 | void setRating(const double &rating); 36 | void setInstalled(bool installed); 37 | void setInQueue(bool inqueue); 38 | void setNonfree(bool nonfree); 39 | 40 | private: 41 | QString m_name; 42 | QString m_version; 43 | unsigned int m_downloadcount; 44 | QString m_downloadsize; 45 | QHash m_category; 46 | QHash m_prettyname; 47 | QString m_exec; 48 | QString m_state; 49 | QString m_search; 50 | double m_rating; 51 | bool m_installed; 52 | bool m_inqueue; 53 | bool m_nonfree; 54 | }; 55 | 56 | #endif // APPLICATION_H 57 | -------------------------------------------------------------------------------- /src/filehandler.cpp: -------------------------------------------------------------------------------- 1 | #include "filehandler.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define SOURCES_FILE "/etc/apt/sources.list" 9 | #define SOURCES_DIR "/etc/apt/sources.list.d" 10 | 11 | FileHandler::FileHandler(QObject *parent) : QObject(parent) 12 | { 13 | 14 | } 15 | 16 | void FileHandler::correctSources() 17 | { 18 | QFile file(SOURCES_FILE); 19 | if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { 20 | emit correctingSourcesFinishedWithError(file.errorString()); 21 | return; 22 | } 23 | 24 | QDir dir(SOURCES_DIR); 25 | dir.setNameFilters(QStringList() << "*.*"); 26 | dir.setFilter(QDir::Files); 27 | 28 | foreach(QString dirFile, dir.entryList()) 29 | { 30 | if(!dir.remove(dirFile)) { 31 | emit correctingSourcesFinishedWithError("Could not delete " + dirFile); 32 | return; 33 | } 34 | } 35 | 36 | QDateTime time = QDateTime::currentDateTime(); 37 | 38 | QTextStream out(&file); 39 | out << "### The Official Pardus Package Repositories ###" << "\n\n" 40 | << "deb http://depo.pardus.org.tr/pardus onyedi main contrib non-free" << "\n" 41 | << "# deb-src http://depo.pardus.org.tr/pardus onyedi main contrib non-free" << "\n\n" 42 | << "deb http://depo.pardus.org.tr/guvenlik onyedi main contrib non-free" << "\n" 43 | << "# deb-src http://depo.pardus.org.tr/guvenlik onyedi main contrib non-free" << "\n\n" 44 | << "### This section generated by Pardus Store at " 45 | << time.toString("hh:mm:ss - dd.MM.yyyy") << " ###\n"; 46 | 47 | file.close(); 48 | emit correctingSourcesFinished(); 49 | } 50 | -------------------------------------------------------------------------------- /src/applicationlistmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef APPLICATIONLISTMODEL_H 2 | #define APPLICATIONLISTMODEL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "application.h" 9 | 10 | enum Roles { 11 | NameRole = Qt::UserRole +1, 12 | VersionRole, 13 | DownloadSizeRole, 14 | CategoryRole, 15 | PrettyNameRole, 16 | ExecRole, 17 | StateRole, 18 | RatingRole, 19 | InstalledRole, 20 | InQueueRole, 21 | NonFreeRole, 22 | SearchRole 23 | }; 24 | 25 | class ApplicationListModel : public QAbstractListModel 26 | { 27 | Q_OBJECT 28 | public: 29 | ApplicationListModel(QObject* parent = 0); 30 | ~ApplicationListModel(); 31 | void addData(const Application &app); 32 | int rowCount(const QModelIndex & parent = QModelIndex()) const; 33 | QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 34 | bool setData(const QModelIndex &index, const QVariant &value, int role); 35 | bool setInstallStatusAtIndex(const int &index, const bool s); 36 | 37 | protected: 38 | QHash roleNames() const; 39 | private: 40 | QList lst; 41 | }; 42 | 43 | 44 | class FilterProxyModel : public QSortFilterProxyModel 45 | { 46 | Q_OBJECT 47 | public: 48 | 49 | FilterProxyModel(QObject* parent = 0); 50 | 51 | ~FilterProxyModel(); 52 | 53 | Q_INVOKABLE void setFilterString(QString s, bool isSearch); 54 | Q_INVOKABLE QString getFilterString() const; 55 | 56 | }; 57 | 58 | class ListCover : public QObject 59 | { 60 | Q_OBJECT 61 | 62 | public: 63 | static void setInstance(ApplicationListModel* p); 64 | static ApplicationListModel* l; 65 | 66 | }; 67 | 68 | 69 | #endif // APPLICATIONLISTMODEL_H 70 | -------------------------------------------------------------------------------- /images/home.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /images/home-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "src/condition.h" 2 | #include "src/helper.h" 3 | #include "src/iconprovider.h" 4 | #include "src/applicationlistmodel.h" 5 | #include "src/singleton.h" 6 | #include "src/namfactory.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | Singleton singleton("pardus-application-store"); 19 | if (!singleton.tryToRun()) { 20 | return 0; 21 | } 22 | qmlRegisterType("ps.condition",1,0,"Condition"); 23 | qmlRegisterType("ps.helper",1,0,"Helper"); 24 | QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling); 25 | QGuiApplication::setWindowIcon(QIcon(":/images/icon.svg")); 26 | QGuiApplication app(argc, argv); 27 | 28 | app.setOrganizationName("pardus"); 29 | app.setOrganizationDomain("www.pardus.org.tr"); 30 | app.setApplicationName("pardus-store"); 31 | app.setFont(QFont("Noto Sans")); 32 | ApplicationListModel listModel; 33 | ListCover::setInstance(&listModel); 34 | FilterProxyModel filterModel; 35 | filterModel.setSourceModel(&listModel); 36 | filterModel.setSortRole(NameRole); 37 | 38 | QTranslator t; 39 | if (t.load(":/translations/pardus-store_" + QLocale::system().name())) { 40 | app.installTranslator(&t); 41 | } else { 42 | qDebug() << "Could not load the translation"; 43 | } 44 | 45 | QQmlApplicationEngine engine; 46 | QQmlContext *context = engine.rootContext(); 47 | context->setContextProperty("applicationModel", &filterModel); 48 | engine.addImageProvider(QLatin1String("application"), new IconProvider); 49 | engine.setNetworkAccessManagerFactory(new NamFactory); 50 | engine.load(QUrl(QLatin1String("qrc:/ui/main.qml"))); 51 | 52 | 53 | return app.exec(); 54 | } 55 | -------------------------------------------------------------------------------- /src/singleton.cpp: -------------------------------------------------------------------------------- 1 | #include "singleton.h" 2 | #include 3 | 4 | namespace 5 | { 6 | 7 | QString generateKeyHash( const QString& key, const QString& salt ) 8 | { 9 | QByteArray data; 10 | 11 | data.append( key.toUtf8() ); 12 | data.append( salt.toUtf8() ); 13 | data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex(); 14 | 15 | return data; 16 | } 17 | 18 | } 19 | 20 | Singleton::Singleton( const QString &key ) 21 | : m_key( key ) 22 | , m_memoryLockKey( generateKeyHash( key, "_m_memoryLockKey" ) ) 23 | , m_sharedMemoryKey( generateKeyHash( key, "_m_sharedMemoryKey" ) ) 24 | , m_sharedMemory( m_sharedMemoryKey ) 25 | , m_systemSemaphore( m_memoryLockKey, 1 ) 26 | { 27 | m_systemSemaphore.acquire(); 28 | { 29 | QSharedMemory fix( m_sharedMemoryKey ); 30 | fix.attach(); 31 | } 32 | m_systemSemaphore.release(); 33 | } 34 | 35 | Singleton::~Singleton() 36 | { 37 | release(); 38 | } 39 | 40 | bool Singleton::isAnotherRunning() 41 | { 42 | if ( m_sharedMemory.isAttached() ) { 43 | return false; 44 | } 45 | m_systemSemaphore.acquire(); 46 | const bool isRunning = m_sharedMemory.attach(); 47 | if ( isRunning ) { 48 | m_sharedMemory.detach(); 49 | } 50 | m_systemSemaphore.release(); 51 | 52 | return isRunning; 53 | } 54 | 55 | bool Singleton::tryToRun() 56 | { 57 | if ( isAnotherRunning() ) { 58 | return false; 59 | } 60 | m_systemSemaphore.acquire(); 61 | const bool result = m_sharedMemory.create( sizeof( quint64 ) ); 62 | m_systemSemaphore.release(); 63 | if ( !result ) { 64 | release(); 65 | return false; 66 | } 67 | return true; 68 | } 69 | 70 | void Singleton::release() 71 | { 72 | m_systemSemaphore.acquire(); 73 | if ( m_sharedMemory.isAttached() ) { 74 | m_sharedMemory.detach(); 75 | } 76 | m_systemSemaphore.release(); 77 | } 78 | -------------------------------------------------------------------------------- /images/star-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 51 | 56 | 57 | -------------------------------------------------------------------------------- /images/star.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 51 | 56 | 57 | -------------------------------------------------------------------------------- /images/all.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /images/email.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 51 | 56 | 57 | -------------------------------------------------------------------------------- /images/email-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 51 | 56 | 57 | -------------------------------------------------------------------------------- /ui/ProgressBarCircle.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.0 2 | import QtQml 2.2 3 | 4 | Item { 5 | id: progressbarcircle 6 | 7 | width: 200 8 | height: 200 9 | 10 | property real value : 0.0 11 | property real maximumValue : 100 12 | property real arcEnd: value * (Math.PI * 1.5) / maximumValue 13 | property real thickness: 10 14 | property int animationDuration: 250 15 | property string colorCircle: "#111111" 16 | property string colorBackground: "#aaaaaa" 17 | 18 | onArcEndChanged: canvas.requestPaint() 19 | 20 | onColorCircleChanged: { 21 | value = 0.0 22 | } 23 | 24 | onValueChanged: { 25 | if(value >= maximumValue) { 26 | value = maximumValue 27 | } 28 | } 29 | 30 | Behavior on value { 31 | enabled: animate 32 | NumberAnimation { 33 | easing.type: Easing.OutExpo 34 | duration: animationDuration 35 | } 36 | } 37 | 38 | Text { 39 | anchors { 40 | horizontalCenter: parent.horizontalCenter 41 | bottom: parent.bottom 42 | bottomMargin: thickness - 3 43 | } 44 | smooth: true 45 | text: value.toFixed(0) + "%" 46 | font.pointSize: thickness * 20 / 9 47 | color: value == 0 ? "#111111" : colorCircle 48 | } 49 | 50 | Canvas { 51 | id: canvas 52 | anchors.fill: parent 53 | anchors.margins: thickness / 3 54 | rotation: 135 55 | layer.enabled: true 56 | layer.smooth: true 57 | onPaint: { 58 | var ctx = getContext("2d") 59 | var x = width / 2 60 | var y = height / 2 61 | var start = 0 62 | var end = parent.arcEnd 63 | ctx.reset() 64 | ctx.beginPath(); 65 | ctx.arc(x, y, (width / 2 - 5) - thickness , 0, Math.PI * 1.5, false) 66 | ctx.lineWidth = thickness 67 | ctx.strokeStyle = colorBackground 68 | ctx.stroke() 69 | ctx.beginPath(); 70 | ctx.arc(x, y, (width / 2 - 5) - thickness , start, end, false) 71 | ctx.lineWidth = thickness 72 | ctx.strokeStyle = colorCircle 73 | ctx.stroke() 74 | 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/networkhandler.h: -------------------------------------------------------------------------------- 1 | #ifndef NETWORKHANDLER_H 2 | #define NETWORKHANDLER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class QNetworkReply; 10 | class QTimer; 11 | class QStringList; 12 | class ApplicationDetail; 13 | class Application; 14 | 15 | class NetworkHandler : public QObject 16 | { 17 | Q_OBJECT 18 | public: 19 | explicit NetworkHandler(const QString &url, const QString &port,int msec = 10000, QObject *parent = 0); 20 | void getApplicationList(); 21 | void getApplicationDetails(const QString &packageName); 22 | void ratingControl(const QString &name, const unsigned int &rating); 23 | void getHomeDetails(); 24 | void sendApplicationInstalled(const QString &name); 25 | void surveyCheck(); 26 | void surveyJoin(const QString &option, const bool sendingForm, const QString &reason, 27 | const QString &website, const QString &mail, const QString &explanation); 28 | void surveyDetail(const QString &name); 29 | QString getMainUrl() const; 30 | 31 | signals: 32 | void appListReceived(const QList &apps); 33 | void appDetailsReceived(const ApplicationDetail &ad); 34 | void appRatingReceived(const double &average, 35 | const unsigned int &individual, 36 | const unsigned int &total, 37 | const QList &rates); 38 | 39 | void homeAppListReceived(const QList &apps); 40 | 41 | void surveyListReceived(const bool isForm, const QString &title, 42 | const QString &question, const QString &mychoice, 43 | const QStringList &choices, const unsigned int ×tamp, 44 | const bool pending); 45 | void surveyDetailReceived(const unsigned int &count, const QString &reason, const QString &website, const QString &explanation); 46 | void surveyJoinResultReceived(const QString &duty, const int &result); 47 | void replyError(const QString &error); 48 | 49 | private slots: 50 | void replyFinished(QNetworkReply *); 51 | void onTimeout(); 52 | 53 | private: 54 | QNetworkAccessManager m_nam; 55 | std::map m_timerMap; 56 | int m_timeoutDuration; 57 | QString m_macId; 58 | QString m_mainUrl; 59 | void parseAppsResponse(const QJsonObject &obj); 60 | void parseDetailsResponse(const QJsonObject &obj); 61 | void parseSurveyResponse(const QJsonObject &obj); 62 | void parseHomeResponse(const QJsonObject &obj); 63 | void parseRatingResponse(const QJsonObject &obj); 64 | void parseStatisticsResponse(const QJsonObject &obj); 65 | 66 | }; 67 | 68 | #endif // NETWORKHANDLER_H 69 | -------------------------------------------------------------------------------- /images/categories.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /images/categories-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /images/website.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /images/website-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /ui/ApplicationList.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Window 2.0 4 | import QtQuick.Controls.Material 2.0 5 | import QtGraphicalEffects 1.0 6 | 7 | Page { 8 | property string previous 9 | property string current 10 | property int visualOffset: 84 11 | property int scrollBarWidth: 16 12 | background: Rectangle { 13 | anchors { 14 | fill: parent 15 | topMargin: 4 16 | bottomMargin: 4 17 | } 18 | 19 | color: "transparent" 20 | 21 | Label { 22 | id: notFoundLabel 23 | font.pointSize: 15 24 | verticalAlignment: Text.AlignVCenter 25 | horizontalAlignment: Text.AlignHCenter 26 | text: qsTr("no match found") 27 | font.capitalization: Font.Capitalize 28 | Material.foreground: accentColor 29 | Material.theme: dark ? Material.Dark : Material.Light 30 | anchors.centerIn: parent 31 | visible: gridView.count === 0 32 | } 33 | 34 | GridView { 35 | id: gridView 36 | clip: true 37 | cellWidth:((width - scrollBarWidth) / 4) < 241.458 ? (width - scrollBarWidth) / 3 : Math.max((width - scrollBarWidth) / 4, 241.45833333333334) 38 | cellHeight: Math.max(height / 4, 234.33333333333334) 39 | cacheBuffer: height * 5 40 | visible: true 41 | interactive: true 42 | snapMode: GridView.SnapToRow 43 | width: parent.width - visualOffset + scrollBarWidth 44 | height: parent.height 45 | anchors.horizontalCenter: parent.horizontalCenter 46 | anchors.horizontalCenterOffset: scrollBarWidth / 2 47 | model: applicationModel 48 | 49 | add: Transition { 50 | enabled: animate 51 | NumberAnimation { 52 | properties: "x,y" 53 | duration: 200 54 | easing.type: Easing.OutExpo 55 | } 56 | } 57 | remove: Transition { 58 | enabled: animate 59 | ParallelAnimation { 60 | NumberAnimation { 61 | property: "opacity" 62 | to: 0 63 | duration: 100 64 | easing.type: Easing.OutExpo 65 | } 66 | NumberAnimation { 67 | properties: "x,y" 68 | to: 100 69 | duration: 100 70 | } 71 | } 72 | } 73 | 74 | delegate: ApplicationDelegate {} 75 | ScrollBar.vertical: ScrollBar { 76 | hoverEnabled: true 77 | active: hovered || pressed 78 | anchors.left: parent.left 79 | anchors.leftMargin: gridView.width - scrollBarWidth - 12 80 | anchors.right: parent.right 81 | anchors.bottom: parent.bottom 82 | Material.theme: dark ? Material.Dark : Material.Light 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /ui/InfoDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.3 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Controls.Material 2.0 4 | 5 | Popup { 6 | id: dialog 7 | property string singleButtonText: qsTr("close") 8 | property bool settingsOrdered: false 9 | property bool settingsButtonOn: false 10 | width: parent.width / 3 - 48 11 | modal: animate 12 | closePolicy: Popup.CloseOnPressOutside 13 | y: parent.height / 2 - height / 2 14 | x: parent.width / 2 - width / 2 15 | Material.background: backgroundColor 16 | Material.elevation: 2 17 | 18 | Column { 19 | anchors.fill: parent 20 | spacing: 12 21 | Label { 22 | id: popupOutputHeader 23 | text: popupHeaderText 24 | anchors { 25 | horizontalCenter: parent.horizontalCenter 26 | } 27 | Material.foreground: textColor 28 | 29 | wrapMode: Text.WordWrap 30 | verticalAlignment: Text.AlignVCenter 31 | horizontalAlignment: Text.AlignHCenter 32 | font.bold: true 33 | } 34 | 35 | Label { 36 | id: popupOutput 37 | text: popupText 38 | width: parent.width 39 | 40 | Material.foreground: textColor 41 | horizontalAlignment: Text.AlignHCenter 42 | wrapMode: Text.WordWrap 43 | verticalAlignment: Text.AlignVCenter 44 | 45 | } 46 | 47 | Row { 48 | anchors.horizontalCenter: parent.horizontalCenter 49 | spacing: 12 50 | Button { 51 | id: setBtn 52 | visible: settingsButtonOn 53 | width: setBtnLabel.width + 24 54 | Material.background: backgroundColor 55 | Material.foreground: textColor 56 | Label { 57 | id: setBtnLabel 58 | text: qsTr("settings") 59 | anchors.centerIn: parent 60 | font.capitalization: Font.Capitalize 61 | } 62 | 63 | onClicked: { 64 | settings.visible = true 65 | //settings.z = 200 66 | settingsOrdered = true 67 | dialog.close() 68 | } 69 | } 70 | 71 | Button { 72 | id: closeBtn 73 | 74 | Material.background: backgroundColor 75 | Material.foreground: textColor 76 | 77 | Label { 78 | text: singleButtonText 79 | anchors.centerIn: parent 80 | font.capitalization: Font.Capitalize 81 | } 82 | 83 | onClicked: { 84 | dialog.close() 85 | } 86 | } 87 | } 88 | } 89 | 90 | onClosed: { 91 | popupHeaderText = qsTr("Something went wrong!") 92 | popupText = "" 93 | singleButtonText = qsTr("close") 94 | if(splashScreen.visible && !settingsOrdered) { 95 | main.close() 96 | } 97 | 98 | if(helper.corrected) { 99 | main.close() 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /ui/ConfirmationDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.3 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Controls.Material 2.0 4 | 5 | Popup { 6 | id: dialog 7 | modal: animate 8 | width: 300 9 | height: buttonContainer.height + imageContainer.height + 48 10 | closePolicy: Popup.NoAutoClose 11 | x: parent.width / 2 - width / 2 12 | y: parent.height / 2 - height / 2 13 | Material.elevation: 2 14 | Material.background: backgroundColor 15 | signal accepted 16 | signal rejected 17 | property alias content: contentLabel.text 18 | property string name: "" 19 | property string from: "" 20 | 21 | Label { 22 | id: contentLabel 23 | anchors { 24 | top: parent.top 25 | bottom: imageContainer.top 26 | bottomMargin: 12 27 | } 28 | Material.foreground: textColor 29 | verticalAlignment: Text.AlignVCenter 30 | horizontalAlignment: Text.AlignHCenter 31 | wrapMode: Text.WordWrap 32 | width: parent.width 33 | 34 | } 35 | 36 | Row { 37 | 38 | id: imageContainer 39 | spacing: 12 40 | anchors { horizontalCenter: parent.horizontalCenter 41 | bottom: buttonContainer.top 42 | bottomMargin: 12 43 | } 44 | 45 | Image { 46 | id: icon 47 | width: 32 48 | height: 32 49 | smooth: true 50 | mipmap: true 51 | antialiasing: true 52 | source: dialog.name === "" ? "" : "image://application/" + getCorrectName(dialog.name) 53 | } 54 | 55 | Label { 56 | id: iconLabel 57 | Material.foreground: textColor 58 | anchors.verticalCenter: parent.verticalCenter 59 | verticalAlignment: Text.AlignVCenter 60 | horizontalAlignment: Text.AlignHCenter 61 | wrapMode: Text.WordWrap 62 | font.bold: true 63 | font.capitalization: Font.Capitalize 64 | text: getCorrectName(dialog.name) 65 | } 66 | } 67 | 68 | Row { 69 | id: buttonContainer 70 | spacing: 12 71 | anchors.horizontalCenter: parent.horizontalCenter 72 | anchors.bottom: parent.bottom 73 | 74 | Button { 75 | id: acceptButton 76 | text: qsTr("yes") 77 | Material.background: backgroundColor 78 | Material.foreground: textColor 79 | onClicked: dialog.accepted() 80 | } 81 | Button { 82 | id: rejectButton 83 | text: qsTr("no") 84 | Material.background: backgroundColor 85 | Material.foreground: textColor 86 | onClicked: dialog.rejected() 87 | } 88 | } 89 | 90 | onAccepted: { 91 | confirmationRemoval(name, from) 92 | dialog.close() 93 | } 94 | onRejected: { 95 | dialog.close() 96 | } 97 | 98 | onClosed: { 99 | name = "" 100 | from = "" 101 | } 102 | 103 | Component.onCompleted: { 104 | content = qsTr("Are you sure you want to remove this application ?") 105 | dialog.height += contentLabel.height + 36 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/applicationdetail.h: -------------------------------------------------------------------------------- 1 | #ifndef APPLICATIONDETAIL_H 2 | #define APPLICATIONDETAIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class Description; 9 | class Section; 10 | class Changelog 11 | { 12 | public: 13 | Changelog(const QStringList &latest, const QString &history, 14 | const unsigned int ×tamp); 15 | Changelog(); 16 | QStringList latest() const; 17 | QString history() const; 18 | unsigned int timestamp() const; 19 | 20 | private: 21 | QStringList m_latest; 22 | QString m_history; 23 | unsigned int m_timestamp; 24 | }; 25 | 26 | inline QStringList Changelog::latest() const { return m_latest; } 27 | inline QString Changelog::history() const { return m_history; } 28 | inline unsigned int Changelog::timestamp() const { return m_timestamp; } 29 | 30 | class ApplicationDetail 31 | { 32 | public: 33 | ApplicationDetail(); 34 | 35 | QStringList changelogLatest() const; 36 | QString changelogHistory() const; 37 | QString changelogDate() const; 38 | unsigned int changelogTimestamp() const; 39 | QString copyright() const; 40 | QString description() const; 41 | unsigned int download() const; 42 | QString license() const; 43 | QString maintainerMail() const; 44 | QString maintainerName() const; 45 | QString name() const; 46 | QStringList screenshots() const; 47 | QString section() const; 48 | QString website() const; 49 | 50 | void setChangelog(const Changelog &changelog); 51 | void setCopyright(const QString ©right); 52 | void setDescriptionList(const QList &descList); 53 | void setDownload(const unsigned int &download); 54 | void setLicense(const QString &license); 55 | void setMaintainer(const QString &mail, const QString &name); 56 | void setName(const QString &name); 57 | void setScreenshots(const QStringList &screenshots); 58 | void setSections(const QList
§ions); 59 | void setWebsite(const QString &website); 60 | 61 | private: 62 | Changelog m_changelog; 63 | QString m_copyright; 64 | QList m_descriptions; 65 | unsigned int m_download; 66 | QString m_license; 67 | QString m_maintainer_mail; 68 | QString m_maintainer_name; 69 | QString m_name; 70 | QStringList m_screenshots; 71 | QList
m_sections; 72 | QString m_website; 73 | }; 74 | 75 | 76 | class Description 77 | { 78 | public: 79 | Description(const QString &lang, const QString &content); 80 | QString language() const; 81 | QString description() const; 82 | 83 | private: 84 | QString m_language, m_description; 85 | }; 86 | 87 | inline QString Description::language() const { return m_language; } 88 | inline QString Description::description() const { return m_description; } 89 | 90 | class Section 91 | { 92 | public: 93 | Section(const QString &lang, const QString &content); 94 | QString language() const; 95 | QString section() const; 96 | 97 | private: 98 | QString m_language, m_section; 99 | }; 100 | 101 | inline QString Section::language() const { return m_language; } 102 | inline QString Section::section() const { return m_section; } 103 | 104 | 105 | 106 | #endif // APPLICATIONDETAIL_H 107 | -------------------------------------------------------------------------------- /images/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /images/settings-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 18 | 20 | 21 | 23 | image/svg+xml 24 | 26 | 27 | 28 | 29 | 30 | 32 | 52 | 57 | 58 | -------------------------------------------------------------------------------- /ui/SplashScreen.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.3 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Controls.Material 2.0 4 | 5 | Pane { 6 | id: splash 7 | anchors.fill: parent 8 | z: 91 9 | opacity: 1.0 10 | property alias label: splashLabel 11 | property alias timer: splashTimer 12 | property alias busy: splashBusy 13 | 14 | Material.background: backgroundColor 15 | 16 | Timer { 17 | id: splashTimer 18 | interval: 800 19 | onTriggered: { 20 | splash.opacity = 0.0 21 | } 22 | } 23 | Behavior on opacity { 24 | enabled: animate 25 | NumberAnimation { 26 | easing.type: Easing.OutExpo 27 | duration: 1000 28 | } 29 | } 30 | onOpacityChanged: { 31 | if(opacity === 0.0) { 32 | splash.visible = false 33 | } 34 | } 35 | 36 | Image { 37 | id: topImage 38 | anchors.horizontalCenter: parent.horizontalCenter 39 | anchors.bottom: parent.verticalCenter 40 | source: "qrc:/images/icon.svg" 41 | opacity: 0.0 42 | Behavior on opacity { 43 | enabled: animate 44 | NumberAnimation { 45 | easing.type: Easing.InExpo 46 | duration: 200 47 | } 48 | } 49 | Component.onCompleted: { 50 | opacity = 1.0 51 | } 52 | onOpacityChanged: { 53 | if(opacity === 1.0) { 54 | appNameLabel.opacity = 1.0 55 | } 56 | } 57 | } 58 | 59 | Label { 60 | id: appNameLabel 61 | text: main.title 62 | smooth: false 63 | verticalAlignment: Text.AlignVCenter 64 | horizontalAlignment: Text.AlignHCenter 65 | Material.foreground: accentColor 66 | font.pointSize: 42 67 | font.capitalization: Font.Capitalize 68 | font.family: pardusFont.name 69 | 70 | anchors.horizontalCenter: parent.horizontalCenter 71 | anchors.top: parent.verticalCenter 72 | anchors.topMargin: 12 73 | 74 | opacity: 0.0 75 | Behavior on opacity { 76 | enabled: animate 77 | NumberAnimation { 78 | easing.type: Easing.InExpo 79 | duration: 200 80 | } 81 | } 82 | } 83 | 84 | Label { 85 | id: splashLabel 86 | font.pointSize: 12 87 | anchors{ 88 | top: appNameLabel.bottom 89 | topMargin: 12 90 | horizontalCenter: parent.horizontalCenter 91 | } 92 | 93 | verticalAlignment: Text.AlignVCenter 94 | horizontalAlignment: Text.AlignHCenter 95 | Material.foreground: textColor 96 | } 97 | 98 | BusyIndicator { 99 | id: splashBusy 100 | height: splashLabel.height + 14 101 | width: height 102 | anchors.verticalCenter: splashLabel.verticalCenter 103 | anchors.left: splashLabel.right 104 | anchors.leftMargin: 20 105 | running: true 106 | Material.accent: accentColor 107 | } 108 | 109 | Component.onCompleted: { 110 | if(updateCache) { 111 | splashLabel.text = qsTr("Updating package manager cache.") 112 | helper.updateCache() 113 | } else { 114 | updateCacheFinished() 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /images/back.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /images/front.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /src/dpkg-progress.cpp: -------------------------------------------------------------------------------- 1 | #include "dpkg-progress.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #define RD_END 0 11 | #define WR_END 1 12 | 13 | static int set_nonblock(int fd) 14 | { 15 | int flags; 16 | 17 | flags = fcntl(fd, F_GETFL); 18 | if (flags < 0) 19 | return -1; 20 | return fcntl(fd, F_SETFL, flags | O_NONBLOCK); 21 | } 22 | 23 | static int set_cloexec(int fd) 24 | { 25 | int flags; 26 | 27 | flags = fcntl(fd, F_GETFD); 28 | if (flags < 0) 29 | return -1; 30 | return fcntl(fd, F_SETFD, flags | FD_CLOEXEC); 31 | } 32 | 33 | static ssize_t xread(int fd, void *buf, size_t len) 34 | { 35 | ssize_t n; 36 | 37 | for (;;) { 38 | n = read(fd, buf, len); 39 | if (n < 0 && errno == EINTR) 40 | continue; 41 | return n; 42 | } 43 | } 44 | 45 | DpkgProgress::DpkgProgress(QObject *parent) : QObject(parent), 46 | m_notifier(nullptr), 47 | pos(&buf[0]), 48 | pipefd(-1), 49 | wrend(-1) 50 | { 51 | } 52 | 53 | DpkgProgress::~DpkgProgress() 54 | { 55 | if (m_notifier) 56 | m_notifier->setEnabled(false); 57 | if (pipefd >= 0) 58 | close(pipefd); 59 | if (wrend >= 0) 60 | close(wrend); 61 | delete m_notifier; 62 | } 63 | 64 | int DpkgProgress::statusFd() 65 | { 66 | int fds[2]; 67 | int err; 68 | 69 | err = ::pipe(fds); 70 | if (err) 71 | return -errno; 72 | if ((err = set_nonblock(fds[RD_END]))) 73 | return -errno; 74 | 75 | m_notifier = new QSocketNotifier(fds[RD_END], QSocketNotifier::Read, this); 76 | connect(m_notifier, SIGNAL(activated(int)), this, SLOT(onReadable(void))); 77 | pipefd = fds[RD_END]; 78 | wrend = fds[WR_END]; 79 | set_cloexec(pipefd); 80 | 81 | return fds[WR_END]; 82 | } 83 | 84 | void DpkgProgress::onReadable() 85 | { 86 | ssize_t nr; 87 | char *nl; 88 | 89 | /* QProcess quirk */ 90 | if (wrend >= 0) { 91 | close(wrend); 92 | wrend = -1; 93 | } 94 | 95 | nr = xread(pipefd, pos, avail()); 96 | if (nr <= 0) { 97 | if (nr == 0) { 98 | m_notifier->setEnabled(false); 99 | notifyProgress(m_line, 100); 100 | return; 101 | } 102 | if (errno != EAGAIN) { 103 | qDebug("Unable to read from pipe!"); 104 | return; 105 | } 106 | } 107 | pos += nr; 108 | 109 | do { 110 | nl = (char *)memchr(buf, '\n', pos - buf); 111 | if (!nl) 112 | break; 113 | 114 | *nl = '\0'; 115 | nl += 1; 116 | processLine(buf); 117 | if (nl < pos) 118 | memmove(buf, nl, pos - nl); 119 | pos = &buf[pos - nl]; 120 | } while (pos - buf > 1); 121 | 122 | if (!avail()) 123 | pos= &buf[0]; 124 | } 125 | 126 | void DpkgProgress::processLine(const char *s) 127 | { 128 | QString str = QString::fromUtf8(s); 129 | m_line = str.split(':', QString::SkipEmptyParts); 130 | if (m_line.size() < 4) 131 | return; 132 | notifyProgress(m_line); 133 | } 134 | 135 | void DpkgProgress::notifyProgress(QStringList line, int percent) 136 | { 137 | bool ok; 138 | 139 | if (percent == -1) { 140 | percent = line[2].toFloat(&ok); 141 | if (!ok) 142 | return; 143 | } 144 | emit dpkgProgress(line[0], line[1], percent, line[3]); 145 | } 146 | -------------------------------------------------------------------------------- /images/download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /images/download-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /src/application.cpp: -------------------------------------------------------------------------------- 1 | #include "application.h" 2 | #include 3 | 4 | Application::Application(const QString &name) 5 | :m_name(name) 6 | { 7 | m_version = ""; 8 | m_downloadcount = 0; 9 | m_downloadsize = ""; 10 | m_category = QHash(); 11 | m_prettyname = QHash(); 12 | m_exec = ""; 13 | m_state = "get"; 14 | m_search = ""; 15 | m_search.append(m_name); 16 | m_rating = 0.0; 17 | m_installed = false; 18 | m_inqueue = false; 19 | m_nonfree = false; 20 | } 21 | 22 | QString Application::name() const 23 | { 24 | return m_name; 25 | } 26 | 27 | QString Application::version() const 28 | { 29 | return m_version; 30 | } 31 | 32 | unsigned int Application::downloadcount() 33 | { 34 | return m_downloadcount; 35 | } 36 | 37 | QString Application::downloadsize() const 38 | { 39 | return m_downloadsize; 40 | } 41 | 42 | QString Application::category() const 43 | { 44 | return m_category.value("en"); 45 | } 46 | 47 | QString Application::categoryLocal() const 48 | { 49 | QLocale systemLocale; 50 | QString locale = systemLocale.name().split("_")[0]; 51 | QString category = m_category.value("en"); 52 | if(m_category.keys().contains(locale) && 53 | m_category.value(locale) != "") { 54 | category = m_category.value(locale); 55 | } 56 | return category; 57 | } 58 | 59 | QString Application::prettyname() const 60 | { 61 | QLocale systemLocale; 62 | QString locale = systemLocale.name().split("_")[0]; 63 | QString prettyname = m_prettyname.value("en"); 64 | if(m_prettyname.keys().contains(locale) && 65 | m_prettyname.value(locale) != "") { 66 | prettyname = m_prettyname.value(locale); 67 | } 68 | return prettyname; 69 | } 70 | 71 | QString Application::exec() const 72 | { 73 | return m_exec; 74 | } 75 | 76 | QString Application::state() const 77 | { 78 | return m_state; 79 | } 80 | 81 | QString Application::search() const 82 | { 83 | return m_search; 84 | } 85 | 86 | double Application::rating() const 87 | { 88 | return m_rating; 89 | } 90 | 91 | bool Application::installed() const 92 | { 93 | return m_installed; 94 | } 95 | 96 | bool Application::nonfree() const 97 | { 98 | return m_nonfree; 99 | } 100 | 101 | bool Application::inqueue() const 102 | { 103 | return m_inqueue; 104 | } 105 | 106 | void Application::setVersion(const QString &version) 107 | { 108 | m_version = version; 109 | } 110 | 111 | void Application::setDownloadcount(const unsigned int &downloadcount) 112 | { 113 | m_downloadcount = downloadcount; 114 | } 115 | 116 | void Application::setDownloadsize(const QString &downloadsize) 117 | { 118 | m_downloadsize = downloadsize; 119 | } 120 | 121 | void Application::setCategory(const QHash &category) 122 | { 123 | m_category = category; 124 | foreach (const QString &key, category.keys()) { 125 | if(m_search.indexOf(category.value(key)) == -1) { 126 | m_search.append(category.value(key)); 127 | } 128 | } 129 | } 130 | 131 | void Application::setPrettyname(const QHash &prettyname) 132 | { 133 | m_prettyname = prettyname; 134 | foreach (const QString &key, prettyname.keys()) { 135 | if(m_search.indexOf(prettyname.value(key)) == -1) { 136 | m_search.append(prettyname.value(key)); 137 | } 138 | } 139 | } 140 | 141 | void Application::setExec(const QString &exec) 142 | { 143 | m_exec = exec; 144 | } 145 | 146 | void Application::setState(const QString &state) 147 | { 148 | m_state = state; 149 | } 150 | 151 | void Application::setRating(const double &rating) 152 | { 153 | m_rating = rating; 154 | } 155 | 156 | void Application::setInstalled(bool installed) 157 | { 158 | m_installed = installed; 159 | } 160 | 161 | 162 | void Application::setInQueue(bool inqueue) 163 | { 164 | m_inqueue = inqueue; 165 | } 166 | 167 | void Application::setNonfree(bool nonfree) 168 | { 169 | m_nonfree = nonfree; 170 | } 171 | -------------------------------------------------------------------------------- /images/rating-stars.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /images/rating-stars-light.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | image/svg+xml -------------------------------------------------------------------------------- /src/applicationlistmodel.cpp: -------------------------------------------------------------------------------- 1 | #include "applicationlistmodel.h" 2 | //#include "application.h" 3 | 4 | ApplicationListModel::ApplicationListModel(QObject *parent) 5 | : QAbstractListModel(parent) 6 | { 7 | 8 | } 9 | 10 | ApplicationListModel::~ApplicationListModel() 11 | { 12 | 13 | } 14 | 15 | void ApplicationListModel::addData(const Application &app) 16 | { 17 | beginInsertRows(QModelIndex(), rowCount(), rowCount()); 18 | lst.append(app); 19 | endInsertRows(); 20 | } 21 | 22 | int ApplicationListModel::rowCount(const QModelIndex &parent) const 23 | { 24 | Q_UNUSED(parent); 25 | return lst.count(); 26 | } 27 | 28 | QVariant ApplicationListModel::data(const QModelIndex &index, int role) const 29 | { 30 | if (index.row() < 0 || index.row() >= lst.count()) 31 | return QVariant(); 32 | 33 | const Application &app = lst[index.row()]; 34 | 35 | switch (role) { 36 | case NameRole: return app.name(); 37 | case VersionRole: return app.version(); 38 | case DownloadSizeRole: return app.downloadsize(); 39 | case CategoryRole: return app.category(); 40 | case PrettyNameRole: return app.prettyname(); 41 | case ExecRole: return app.exec(); 42 | case StateRole: return app.state(); 43 | case InstalledRole: return app.installed(); 44 | case InQueueRole: return app.inqueue(); 45 | case NonFreeRole: return app.nonfree(); 46 | case SearchRole: return app.search(); 47 | default: return QVariant(); 48 | } 49 | return QVariant(); 50 | } 51 | 52 | bool ApplicationListModel::setData(const QModelIndex &index, const QVariant &value, int role) 53 | { 54 | if(index.row() < lst.size() && index.row() >= 0 ) { 55 | 56 | if(role == InstalledRole) { 57 | bool status = value.toBool(); 58 | lst[index.row()].setInstalled(status); 59 | if(status) { 60 | lst[index.row()].setState("installed"); 61 | } else { 62 | lst[index.row()].setState("get"); 63 | } 64 | } else if(role == InQueueRole) { 65 | lst[index.row()].setInQueue(value.toBool()); 66 | } else if(role == StateRole) { 67 | lst[index.row()].setState(value.toString()); 68 | } 69 | 70 | dataChanged(index,index); 71 | return true; 72 | } 73 | return false; 74 | } 75 | 76 | bool ApplicationListModel::setInstallStatusAtIndex(const int &index, const bool s) 77 | { 78 | if(index < lst.size() && index >= 0 ) { 79 | 80 | lst[index].setInstalled(s); 81 | if(s) { 82 | lst[index].setState("installed"); 83 | } else { 84 | lst[index].setState("get"); 85 | } 86 | dataChanged(this->index(index),this->index(index)); 87 | return true; 88 | } 89 | return false; 90 | } 91 | 92 | QHash ApplicationListModel::roleNames() const { 93 | QHash roles; 94 | roles[NameRole] = "name"; 95 | roles[VersionRole] = "version"; 96 | roles[DownloadSizeRole] = "dsize"; 97 | roles[CategoryRole] = "category"; 98 | roles[PrettyNameRole] = "prettyname"; 99 | roles[ExecRole] = "exec"; 100 | roles[StateRole] = "delegatestate"; 101 | roles[RatingRole] = "rating"; 102 | roles[InstalledRole] = "installed"; 103 | roles[InQueueRole] = "inqueue"; 104 | roles[NonFreeRole] = "nonfree"; 105 | roles[SearchRole] = "search"; 106 | return roles; 107 | } 108 | 109 | FilterProxyModel::FilterProxyModel(QObject *parent) 110 | :QSortFilterProxyModel(parent) 111 | { 112 | this->setFilterRole(CategoryRole); 113 | } 114 | 115 | FilterProxyModel::~FilterProxyModel() 116 | { 117 | 118 | } 119 | 120 | void FilterProxyModel::setFilterString(QString s, bool isSearch) 121 | { 122 | setFilterCaseSensitivity(Qt::CaseInsensitive); 123 | if(s == "") { 124 | setFilterRole(isSearch ? NameRole : CategoryRole); 125 | setFilterFixedString(s); 126 | } else { 127 | setFilterRole(isSearch ? SearchRole : CategoryRole); 128 | setFilterRegExp(s); 129 | } 130 | } 131 | 132 | QString FilterProxyModel::getFilterString() const 133 | { 134 | return this->filterRegExp().pattern(); 135 | } 136 | 137 | ApplicationListModel *ListCover::l = 0; 138 | 139 | void ListCover::setInstance(ApplicationListModel *p) 140 | { 141 | l=p; 142 | } 143 | 144 | -------------------------------------------------------------------------------- /images/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 31 | 33 | 53 | 58 | 59 | -------------------------------------------------------------------------------- /images/search-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 22 | 24 | image/svg+xml 25 | 27 | 28 | 29 | 30 | 31 | 33 | 53 | 58 | 59 | -------------------------------------------------------------------------------- /src/packagehandler.cpp: -------------------------------------------------------------------------------- 1 | #include "packagehandler.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | //#include 7 | //#include 8 | 9 | #include "dpkg-progress.h" 10 | 11 | PackageHandler::PackageHandler(QObject *parent) : QObject(parent), 12 | dpkg(nullptr), m_percent(0), m_status("") 13 | { 14 | p = new QProcess(); 15 | QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 16 | env.insert("LC_ALL","C"); 17 | p->setEnvironment(env.toStringList()); 18 | connect(p,SIGNAL(finished(int)),this,SIGNAL(finished(int))); 19 | connect(p,SIGNAL(finished(int)),this, SLOT(onFinished(int))); 20 | 21 | } 22 | 23 | PackageHandler::~PackageHandler() 24 | { 25 | p->deleteLater(); 26 | } 27 | 28 | void PackageHandler::updateCache() 29 | { 30 | p->start("apt update"); 31 | } 32 | 33 | void PackageHandler::install(const QString &pkg) 34 | { 35 | int statusFd; 36 | QString cmd = "apt-get install -y "; 37 | dpkg = new DpkgProgress(); 38 | 39 | statusFd = dpkg->statusFd(); 40 | if (statusFd >= 0) { 41 | cmd.append("-o APT::Status-Fd=%1 %2"); 42 | cmd = cmd.arg(statusFd).arg(pkg); 43 | connect(dpkg, SIGNAL(dpkgProgress(QString,QString,int,QString)), 44 | this, SLOT(onDpkgProgress(QString,QString,int,QString))); 45 | } else { 46 | /* Unable to get progress information */ 47 | delete dpkg; 48 | dpkg = nullptr; 49 | cmd.append("%1"); 50 | cmd = cmd.arg(pkg); 51 | } 52 | p->start(cmd); 53 | } 54 | 55 | void PackageHandler::onFinished(int) 56 | { 57 | if (dpkg) { 58 | dpkg->disconnect(); 59 | dpkg->deleteLater(); 60 | dpkg = nullptr; 61 | } 62 | } 63 | 64 | void PackageHandler::onDpkgProgress(const QString &status, const QString &pkg, 65 | int value, const QString &desc) 66 | { 67 | m_status = status; 68 | m_percent = value; 69 | emit dpkgProgressStatus(status, pkg, value, desc); 70 | } 71 | 72 | void PackageHandler::remove(const QString &pkg) 73 | { 74 | int statusFd; 75 | QString cmd = "apt-get remove -y "; 76 | dpkg = new DpkgProgress(); 77 | 78 | statusFd = dpkg->statusFd(); 79 | if (statusFd >= 0) { 80 | cmd.append("-o APT::Status-Fd=%1 %2"); 81 | cmd = cmd.arg(statusFd).arg(pkg); 82 | connect(dpkg, SIGNAL(dpkgProgress(QString,QString,int,QString)), 83 | this, SLOT(onDpkgProgress(QString,QString,int,QString))); 84 | } else { 85 | /* Unable to get progress information */ 86 | delete dpkg; 87 | dpkg = nullptr; 88 | cmd.append("%1"); 89 | cmd = cmd.arg(pkg); 90 | } 91 | p->start(cmd); 92 | } 93 | 94 | bool PackageHandler::terminate() 95 | { 96 | if(m_status == "dlstatus" && m_percent < 99) { 97 | p->terminate(); 98 | if (dpkg) { 99 | dpkg->disconnect(); 100 | dpkg->deleteLater(); 101 | dpkg = nullptr; 102 | } 103 | return true; 104 | } else { 105 | return false; 106 | } 107 | } 108 | 109 | QString PackageHandler::getPolicy(const QString &pkg) const 110 | { 111 | QProcess process; 112 | QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 113 | env.insert("LC_ALL","C"); 114 | process.setEnvironment(env.toStringList()); 115 | process.start("apt-cache policy " + pkg); 116 | 117 | process.waitForFinished(-1); 118 | 119 | QString out = QString::fromLatin1(process.readAllStandardOutput()); 120 | process.close(); 121 | return out; 122 | } 123 | 124 | QString PackageHandler::getShow(const QString &pkg) const 125 | { 126 | QProcess process; 127 | QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 128 | env.insert("LC_ALL","C"); 129 | process.setEnvironment(env.toStringList()); 130 | process.start("apt-cache show " + pkg); 131 | 132 | process.waitForFinished(-1); 133 | 134 | QString out = QString::fromLatin1(process.readAllStandardOutput()); 135 | process.close(); 136 | return out; 137 | } 138 | 139 | QString PackageHandler::getSearch(const QString &pkg) const 140 | { 141 | QProcess process; 142 | process.start("apt-cache search " + pkg); 143 | 144 | process.waitForFinished(); 145 | 146 | QString out = QString::fromLatin1(process.readAllStandardOutput()); 147 | process.close(); 148 | return out; 149 | } 150 | 151 | QByteArray PackageHandler::getError() 152 | { 153 | return p->readAllStandardError(); 154 | } 155 | 156 | QByteArray PackageHandler::getOutput() 157 | { 158 | return p->readAllStandardOutput(); 159 | } 160 | -------------------------------------------------------------------------------- /ui/QueueDialog.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.3 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Controls.Material 2.0 4 | import ps.condition 1.0 5 | 6 | Popup { 7 | id: dialogRoot 8 | closePolicy: Popup.CloseOnPressOutside 9 | Material.background: backgroundColor 10 | Material.elevation: 3 11 | width: navigationBarWidth 12 | z: 99 13 | x: 0 14 | y: parent.height - height - 26 15 | 16 | 17 | property alias repeater: repeaterQueue 18 | property alias title: queuePopupTitle 19 | 20 | Behavior on y { 21 | enabled: animate 22 | NumberAnimation { 23 | easing.type: Easing.OutExpo 24 | duration: 600 25 | } 26 | } 27 | 28 | MouseArea { 29 | anchors.centerIn: parent 30 | width: parent.width + 24 31 | height: parent.height + 24 32 | hoverEnabled: true 33 | } 34 | 35 | Label { 36 | id: queuePopupTitle 37 | text: qsTr("queue") 38 | Material.foreground: accentColor 39 | anchors.horizontalCenter: parent.horizontalCenter 40 | anchors.top: parent.top 41 | verticalAlignment: Text.AlignVCenter 42 | horizontalAlignment: Text.AlignHCenter 43 | font.capitalization: Font.Capitalize 44 | } 45 | 46 | Column { 47 | spacing: 12 48 | anchors.horizontalCenter: parent.horizontalCenter 49 | anchors.bottom: parent.bottom 50 | width: parent.width 51 | height: parent.height - queuePopupTitle.height 52 | Repeater { 53 | id: repeaterQueue 54 | model: processQueue 55 | 56 | Item { 57 | width: parent.width 58 | height: 24 59 | 60 | Label { 61 | id: nameLabel 62 | color: textColor 63 | anchors.verticalCenter: parent.verticalCenter 64 | text: modelData.split(" ")[0] 65 | verticalAlignment: Text.AlignVCenter 66 | font.capitalization: Font.Capitalize 67 | horizontalAlignment: Text.AlignLeft 68 | anchors.left: parent.left 69 | } 70 | 71 | Label { 72 | id: dutyLabel 73 | Material.foreground: textColor 74 | Material.theme: dark ? Material.Dark : Material.Light 75 | anchors.verticalCenter: parent.verticalCenter 76 | verticalAlignment: Text.AlignVCenter 77 | horizontalAlignment: Text.AlignRight 78 | font.capitalization: Font.Capitalize 79 | enabled: false 80 | anchors { 81 | right: cancelBtn.left 82 | rightMargin: 6 83 | } 84 | text: index === 0 ? getConditionString(processingCondition) : (modelData.split(" ")[1] === "true" ? qsTr("remove") : qsTr("install")) 85 | font.pointSize: 9 86 | } 87 | 88 | Rectangle { 89 | id: cancelBtn 90 | visible: index !== 0 ? true : (processingCondition === Condition.Downloading) 91 | color: "#F44336" 92 | width: 24 93 | height: width 94 | radius: 2 95 | anchors.right: parent.right 96 | Label { 97 | text: "X" 98 | Material.foreground: "#fafafa" 99 | anchors.centerIn: parent 100 | verticalAlignment: Text.AlignVCenter 101 | font.capitalization: Font.Capitalize 102 | font.bold: true 103 | } 104 | MouseArea { 105 | id: cancelBtnMa 106 | z: 100 107 | anchors { 108 | fill: parent 109 | } 110 | property string disqueuedApplication: "" 111 | onPressed: cancelBtn.color = "#EF9A9A" 112 | onPressAndHold: cancelBtn.color = "#EF9A9A" 113 | onReleased: cancelBtn.color = "#F44336" 114 | onClicked: { 115 | if(index === 0) { 116 | terminateFromDialog(modelData.split(" ")[0]) 117 | } else { 118 | disQueue(modelData.split(" ")[0]) 119 | } 120 | } 121 | } 122 | } 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /ui/SearchBar.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Controls.Material 2.0 4 | 5 | Item { 6 | id: container 7 | width: 161.625 8 | height: 32 9 | property int searchBarBorderWidth: 1 10 | property int radiusValue: 3 11 | property int marginValue: 22 12 | property string searchBarColor: backgroundColor 13 | 14 | Rectangle { 15 | id: searchBarBorder 16 | width: parent.width 17 | height: parent.height 18 | radius: container.radiusValue 19 | color: searchText.focus ? accentColor : oppsiteBackgroundColor 20 | 21 | anchors.centerIn: parent 22 | 23 | Rectangle { 24 | id: searchBar 25 | width: parent.width - container.searchBarBorderWidth * 2 26 | height: parent.height - container.searchBarBorderWidth * 2 27 | radius: container.radiusValue 28 | color: container.searchBarColor 29 | 30 | anchors.centerIn: parent 31 | 32 | MouseArea { 33 | id: searchBarMa 34 | anchors.fill: parent 35 | hoverEnabled: true 36 | cursorShape: Qt.IBeamCursor 37 | acceptedButtons: Qt.NoButton 38 | 39 | } 40 | 41 | TextInput { 42 | id: searchText 43 | width: parent.width - clearIcon.width - container.marginValue 44 | color: textColor 45 | font.pointSize: 16 46 | horizontalAlignment: Text.AlignHCenter 47 | clip: true 48 | anchors.verticalCenter: parent.verticalCenter 49 | anchors.left: parent.left 50 | anchors.leftMargin: 12 51 | anchors.right: clearIcon.left 52 | anchors.rightMargin: 6 53 | 54 | onActiveFocusChanged: { 55 | if(activeFocus && searchBarMa.containsMouse) { 56 | if(stackView.depth === 3) { 57 | stackView.pop() 58 | } 59 | selectedMenu = "categories" 60 | selectedCategory = "all" 61 | expanded = true 62 | applicationModel.setFilterString(searchText.text.trim(), true) 63 | } 64 | 65 | } 66 | 67 | Keys.onEscapePressed: { 68 | text = "" 69 | focus = false 70 | } 71 | onTextChanged: { 72 | applicationModel.setFilterString(searchText.text.trim(), true) 73 | } 74 | 75 | } 76 | 77 | Image { 78 | id: clearIcon 79 | height: searchText.height - 12 80 | width: height 81 | sourceSize: Qt.size(width,height) 82 | source: "qrc:/images/clear" + (dark ? ".svg" : "-dark.svg") 83 | visible: searchText.text 84 | 85 | anchors.verticalCenter: parent.verticalCenter 86 | anchors.right: parent.right 87 | anchors.rightMargin: 3 88 | 89 | MouseArea { 90 | id: maClear 91 | anchors.fill: parent 92 | hoverEnabled: true 93 | onClicked: { 94 | searchText.text = "" 95 | } 96 | 97 | } 98 | } 99 | } 100 | 101 | 102 | Image { 103 | id: searchIcon 104 | height: searchBar.height - 10 105 | width: height 106 | visible: !searchText.text 107 | source: "qrc:/images/search" + (dark ? ".svg" : "-dark.svg") 108 | sourceSize: Qt.size(width, height) 109 | anchors{ 110 | left: parent.left 111 | leftMargin: 8 112 | verticalCenter: parent.verticalCenter 113 | } 114 | } 115 | 116 | Label { 117 | id: placeHolder 118 | Material.theme: dark ? Material.Dark : Material.Light 119 | enabled: false 120 | height: searchBar.height 121 | visible: !searchText.text 122 | text: qsTr("Search an application") 123 | fontSizeMode: Text.HorizontalFit 124 | verticalAlignment: Text.AlignVCenter 125 | horizontalAlignment: Text.AlignHCenter 126 | anchors { 127 | left: searchIcon.right 128 | leftMargin: 5 129 | right: parent.right 130 | rightMargin: 8 131 | verticalCenter: parent.verticalCenter 132 | } 133 | } 134 | 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/applicationdetail.cpp: -------------------------------------------------------------------------------- 1 | #include "applicationdetail.h" 2 | #include 3 | 4 | ApplicationDetail::ApplicationDetail() 5 | { 6 | m_name = ""; 7 | m_copyright = ""; 8 | m_descriptions = QList(); 9 | m_download = 0; 10 | m_license = ""; 11 | m_maintainer_mail = ""; 12 | m_maintainer_name = ""; 13 | m_screenshots = QStringList(""); 14 | m_sections = QList
(); 15 | m_website = ""; 16 | } 17 | 18 | QStringList ApplicationDetail::changelogLatest() const 19 | { 20 | return m_changelog.latest(); 21 | } 22 | 23 | QString ApplicationDetail::changelogHistory() const 24 | { 25 | return m_changelog.history(); 26 | } 27 | 28 | unsigned int ApplicationDetail::changelogTimestamp() const 29 | { 30 | return m_changelog.timestamp(); 31 | } 32 | 33 | QString ApplicationDetail::copyright() const 34 | { 35 | return m_copyright; 36 | } 37 | 38 | QString ApplicationDetail::description() const 39 | { 40 | QLocale systemLocale; 41 | QString locale = systemLocale.name().split("_")[0]; 42 | QString language; 43 | QString description = ""; 44 | for(int i=0; i< m_descriptions.size(); i++) { 45 | language = m_descriptions.at(i).language(); 46 | if (language.compare("en") == 0) { 47 | description = m_descriptions.at(i).description(); 48 | } else if (language.compare(locale) == 0) { 49 | if(m_descriptions.at(i).description() != "") { 50 | description = m_descriptions.at(i).description(); 51 | } 52 | } 53 | } 54 | 55 | return description; 56 | } 57 | 58 | unsigned int ApplicationDetail::download() const 59 | { 60 | return m_download; 61 | } 62 | 63 | QString ApplicationDetail::license() const 64 | { 65 | return m_license; 66 | } 67 | 68 | QString ApplicationDetail::maintainerMail() const 69 | { 70 | return m_maintainer_mail; 71 | } 72 | 73 | QString ApplicationDetail::maintainerName() const 74 | { 75 | return m_maintainer_name; 76 | } 77 | 78 | QString ApplicationDetail::name() const 79 | { 80 | return m_name; 81 | } 82 | 83 | QStringList ApplicationDetail::screenshots() const 84 | { 85 | return m_screenshots; 86 | } 87 | 88 | QString ApplicationDetail::section() const 89 | { 90 | QLocale systemLocale; 91 | QString locale = systemLocale.name().split("_")[0]; 92 | QString language; 93 | QString section = ""; 94 | for(int i=0; i< m_sections.size(); i++) { 95 | language = m_sections.at(i).language(); 96 | if (language.compare("en") == 0) { 97 | section = m_sections.at(i).section(); 98 | } else if (language.compare(locale) == 0) { 99 | if(m_sections.at(i).section() != "") { 100 | section = m_sections.at(i).section(); 101 | } 102 | } 103 | } 104 | return section; 105 | } 106 | 107 | QString ApplicationDetail::website() const 108 | { 109 | return m_website; 110 | } 111 | 112 | void ApplicationDetail::setChangelog(const Changelog &changelog) 113 | { 114 | m_changelog = changelog; 115 | } 116 | 117 | void ApplicationDetail::setCopyright(const QString ©right) 118 | { 119 | m_copyright = copyright; 120 | } 121 | 122 | void ApplicationDetail::setDescriptionList(const QList &descList) 123 | { 124 | m_descriptions = descList; 125 | } 126 | 127 | void ApplicationDetail::setDownload(const unsigned int &download) 128 | { 129 | m_download = download; 130 | } 131 | 132 | void ApplicationDetail::setLicense(const QString &license) 133 | { 134 | m_license = license; 135 | } 136 | 137 | void ApplicationDetail::setMaintainer(const QString &mail, const QString &name) 138 | { 139 | m_maintainer_mail = mail; 140 | m_maintainer_name = name; 141 | } 142 | 143 | void ApplicationDetail::setName(const QString &name) 144 | { 145 | m_name = name; 146 | } 147 | 148 | void ApplicationDetail::setScreenshots(const QStringList &screenshots) 149 | { 150 | m_screenshots = screenshots; 151 | } 152 | 153 | void ApplicationDetail::setSections(const QList
§ions) 154 | { 155 | m_sections = sections; 156 | } 157 | 158 | void ApplicationDetail::setWebsite(const QString &website) 159 | { 160 | m_website = website; 161 | } 162 | 163 | Description::Description(const QString &lang, const QString &content): 164 | m_language(lang), m_description(content) 165 | { 166 | 167 | } 168 | 169 | Section::Section(const QString &lang, const QString &content): 170 | m_language(lang), m_section(content) 171 | { 172 | 173 | } 174 | 175 | Changelog::Changelog(const QStringList &latest, const QString &history, const unsigned int ×tamp): 176 | m_latest(latest), m_history(history), m_timestamp(timestamp) 177 | { 178 | 179 | } 180 | 181 | Changelog::Changelog() 182 | { 183 | m_latest = QStringList(); 184 | m_history = ""; 185 | m_timestamp = 0; 186 | } 187 | -------------------------------------------------------------------------------- /images/clear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 41 | 44 | 45 | 47 | 48 | 50 | image/svg+xml 51 | 53 | 54 | 55 | 56 | 57 | 62 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 97 | 100 | 103 | 106 | 109 | 112 | 115 | 118 | 122 | 126 | 136 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /images/clear-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 19 | 21 | 41 | 44 | 45 | 47 | 48 | 50 | image/svg+xml 51 | 53 | 54 | 55 | 56 | 57 | 62 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 97 | 100 | 103 | 106 | 109 | 112 | 115 | 118 | 122 | 126 | 136 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /ui/SurveyDetail.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Controls.Material 2.0 4 | 5 | Item { 6 | visible: false 7 | property string surveySelectedApp: "" 8 | property int count 9 | property string reason 10 | property string website 11 | property string explanation 12 | 13 | function detailsReceived(c, r, w, e) { 14 | count = c 15 | reason = r 16 | website = w 17 | explanation = e 18 | } 19 | 20 | Component.onCompleted: { 21 | helper.getSurveyDetail(surveySelectedApp) 22 | surveyDetailsReceived.connect(detailsReceived) 23 | } 24 | 25 | Button { 26 | id: surveyBackButton 27 | z: 92 28 | height: 54 29 | width: height * 2 / 3 30 | Material.background: "#515151" 31 | anchors { 32 | top: parent.top 33 | topMargin: - 6 34 | left: parent.left 35 | } 36 | 37 | Image { 38 | width: parent.height - 24 39 | anchors.centerIn: parent 40 | fillMode: Image.PreserveAspectFit 41 | sourceSize.width: width 42 | sourceSize.height: width 43 | smooth: true 44 | source: "qrc:/images/back.svg" 45 | } 46 | 47 | onClicked: { 48 | surveyStackView.pop(null) 49 | } 50 | } 51 | 52 | Label { 53 | anchors { 54 | left: surveyBackButton.right 55 | leftMargin: 12 56 | right: parent.right 57 | top: surveyBackButton.top 58 | bottom: surveyBackButton.bottom 59 | } 60 | color: secondaryTextColor 61 | text: qsTr("Vote count") + " : " + count 62 | verticalAlignment: Text.AlignVCenter 63 | horizontalAlignment: Text.AlignHCenter 64 | font.bold: true 65 | font.pointSize:15 66 | } 67 | 68 | Column { 69 | anchors { 70 | left: parent.left 71 | right: parent.right 72 | top: surveyBackButton.bottom 73 | bottom: parent.bottom 74 | } 75 | 76 | spacing: 24 77 | 78 | Row { 79 | id: surveyDetailHeader 80 | spacing: 12 81 | height: surveyBackButton.height 82 | anchors.horizontalCenter: parent.horizontalCenter 83 | 84 | Image { 85 | id:surveyAppIcon 86 | height: parent.height 87 | width: height 88 | anchors { 89 | verticalCenter: parent.verticalCenter 90 | } 91 | verticalAlignment: Image.AlignVCenter 92 | fillMode: Image.PreserveAspectFit 93 | visible: true 94 | source: surveySelectedApp !== "" ? "image://application/" + getCorrectName(surveySelectedApp) : 95 | "image://application/image-missing" 96 | sourceSize.width: width 97 | sourceSize.height: height 98 | smooth: true 99 | } 100 | 101 | Label { 102 | anchors { 103 | verticalCenter: parent.verticalCenter 104 | } 105 | color: textColor 106 | text: surveySelectedApp 107 | verticalAlignment: Text.AlignVCenter 108 | horizontalAlignment: Text.AlignHCenter 109 | font.capitalization: Font.Capitalize 110 | font.bold: true 111 | font.pointSize:18 112 | } 113 | } 114 | 115 | Flickable { 116 | id: surveyAppDescriptionFlick 117 | clip: true 118 | width: parent.width 119 | height: survey.height - surveyDetailHeader.height - 96 120 | contentHeight: surveyAppDetailsColumn.height + 6 121 | ScrollBar.vertical: ScrollBar { } 122 | flickableDirection: Flickable.VerticalFlick 123 | 124 | Column { 125 | id:surveyAppDetailsColumn 126 | width: parent.width 127 | spacing: 12 128 | Label { 129 | width: parent.width - 12 130 | wrapMode: Text.WordWrap 131 | verticalAlignment: Text.AlignVCenter 132 | horizontalAlignment: Text.AlignLeft 133 | text: qsTr("Why we should vote for this ?") 134 | color: textColor 135 | font.pointSize: 11 136 | font.bold: true 137 | } 138 | 139 | Label { 140 | width: parent.width - 12 141 | wrapMode: Text.WordWrap 142 | verticalAlignment: Text.AlignVCenter 143 | horizontalAlignment: Text.AlignLeft 144 | text: reason 145 | color: secondaryTextColor 146 | } 147 | 148 | Seperator { 149 | height: 5 150 | lineColor: seperatorColor 151 | } 152 | 153 | Label { 154 | width: parent.width - 12 155 | wrapMode: Text.WordWrap 156 | verticalAlignment: Text.AlignVCenter 157 | horizontalAlignment: Text.AlignLeft 158 | text: qsTr("Detailed explanation") 159 | color: textColor 160 | font.pointSize: 11 161 | font.bold: true 162 | } 163 | 164 | Label { 165 | width: parent.width - 12 166 | wrapMode: Text.WordWrap 167 | verticalAlignment: Text.AlignVCenter 168 | horizontalAlignment: Text.AlignLeft 169 | text: explanation 170 | color: secondaryTextColor 171 | MouseArea { 172 | anchors.fill: parent 173 | acceptedButtons: Qt.NoButton 174 | cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor 175 | } 176 | 177 | onLinkActivated: { 178 | helper.openUrl(link) 179 | } 180 | } 181 | 182 | Seperator { 183 | height: 5 184 | lineColor: seperatorColor 185 | } 186 | 187 | Label { 188 | width: parent.width - 12 189 | wrapMode: Text.WordWrap 190 | verticalAlignment: Text.AlignVCenter 191 | horizontalAlignment: Text.AlignLeft 192 | text: qsTr("Where can we be more informed about this ?") 193 | color: textColor 194 | font.pointSize: 11 195 | font.bold: true 196 | } 197 | 198 | Label { 199 | width: parent.width - 12 200 | verticalAlignment: Text.AlignVCenter 201 | horizontalAlignment: Text.AlignLeft 202 | text: website 203 | color: surveyDetailWebsiteMa.containsMouse ? textColor : secondaryTextColor 204 | elide: Text.ElideRight 205 | font.underline: surveyDetailWebsiteMa.containsMouse 206 | MouseArea { 207 | id: surveyDetailWebsiteMa 208 | anchors.fill: parent 209 | hoverEnabled: true 210 | cursorShape: Qt.PointingHandCursor 211 | onClicked: { 212 | helper.openUrl(website) 213 | } 214 | } 215 | } 216 | } 217 | } 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/helper.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPER_H 2 | #define HELPER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "applicationlistmodel.h" 10 | 11 | class FileHandler; 12 | class PackageHandler; 13 | class NetworkHandler; 14 | class ApplicationDetail; 15 | class QSettings; 16 | 17 | class Helper : public QObject 18 | { 19 | Q_OBJECT 20 | Q_PROPERTY(bool processing 21 | READ processing 22 | NOTIFY processingFinished 23 | NOTIFY processingFinishedWithError 24 | NOTIFY processingStatus 25 | NOTIFY fetchingAppListFinished 26 | NOTIFY gatheringLocalDetailFinished) 27 | Q_PROPERTY(QString surveychoice 28 | READ surveychoice 29 | NOTIFY surveychoiceChanged 30 | NOTIFY surveyListReceived 31 | NOTIFY surveyJoinSuccess) 32 | Q_PROPERTY(bool animate 33 | READ animate 34 | WRITE setAnimate 35 | NOTIFY animateChanged) 36 | Q_PROPERTY(bool update 37 | READ update 38 | WRITE setUpdate 39 | NOTIFY updateChanged) 40 | Q_PROPERTY(unsigned int ratio 41 | READ ratio 42 | WRITE setRatio 43 | NOTIFY ratioChanged) 44 | Q_PROPERTY(bool usedark 45 | READ usedark 46 | WRITE setUsedark 47 | NOTIFY usedarkChanged) 48 | Q_PROPERTY(QString version 49 | READ version 50 | NOTIFY versionChanged) 51 | Q_PROPERTY(bool corrected 52 | READ corrected 53 | NOTIFY correctingFinished 54 | NOTIFY correctingFinishedWithError) 55 | Q_PROPERTY(bool erroronreply 56 | READ erroronreply 57 | NOTIFY replyError) 58 | Q_PROPERTY(bool detailsopened 59 | READ detailsopened 60 | WRITE setDetailsopened 61 | NOTIFY detailsReceived) 62 | Q_PROPERTY(unsigned int rating 63 | READ rating 64 | NOTIFY ratingDetailReceived) 65 | Q_PROPERTY(bool homeLoaded 66 | READ homeLoaded 67 | NOTIFY homeReceived) 68 | Q_PROPERTY(QStringList categorylist READ categorylist NOTIFY categorylistChanged) 69 | 70 | public: 71 | explicit Helper(QObject *parent = 0); 72 | ~Helper(); 73 | bool processing() const; 74 | bool animate() const; 75 | void setAnimate(bool a); 76 | bool update() const; 77 | void setUpdate(bool u); 78 | unsigned int ratio() const; 79 | void setRatio(const unsigned int &r); 80 | bool usedark() const; 81 | void setUsedark(bool d); 82 | QString url() const; 83 | QString port() const; 84 | void setUrl(const QString &u); 85 | void setPort(const QString &p); 86 | QString surveychoice() const; 87 | QString version() const; 88 | bool corrected() const; 89 | bool erroronreply() const; 90 | bool detailsopened () const; 91 | void setDetailsopened(bool d); 92 | unsigned int rating(); 93 | bool homeLoaded(); 94 | QStringList categorylist() const; 95 | 96 | Q_INVOKABLE void updateCache(); 97 | Q_INVOKABLE void install(const QString &pkg); 98 | Q_INVOKABLE void remove(const QString &pkg); 99 | Q_INVOKABLE bool terminate(); 100 | Q_INVOKABLE void getAppList(); 101 | Q_INVOKABLE void getAppDetails(const QString &pkg); 102 | Q_INVOKABLE void getHomeScreenDetails(); 103 | Q_INVOKABLE void ratingControl(const QString &name, const unsigned int &rating = 0); 104 | Q_INVOKABLE void surveyCheck(); 105 | Q_INVOKABLE void surveyJoin(const QString &option, const bool sendingForm, const QString &reason = "", 106 | const QString &website = "", const QString &mail = "", 107 | const QString &explanation = ""); 108 | Q_INVOKABLE void getSurveyDetail(const QString &name); 109 | Q_INVOKABLE void systemNotify(const QString &pkg, 110 | const QString &title, 111 | const QString &content); 112 | Q_INVOKABLE QString getMainUrl() const; 113 | Q_INVOKABLE void correctSourcesList(); 114 | Q_INVOKABLE void openUrl(const QString &url); 115 | Q_INVOKABLE void runCommand(const QString &cmd); 116 | Q_INVOKABLE void sendStatistics(const QString &appname); 117 | Q_INVOKABLE void updatePackageInstalledStatus(const QString &pkg, const bool s); 118 | Q_INVOKABLE QString getCategoryLocal(const QString &c) const; 119 | 120 | private: 121 | bool p; 122 | QString m_surveychoice; 123 | QString v; 124 | bool m_corrected; 125 | bool m_erroronreply; 126 | bool m_detailsopened; 127 | unsigned int m_rating; 128 | bool m_homeloaded; 129 | FileHandler *fh; 130 | PackageHandler *ph; 131 | QList m_fakelist; 132 | QList m_homelist; 133 | ListCover lc; 134 | NetworkHandler *nh; 135 | QSettings *s; 136 | void fillTheList(); 137 | 138 | bool m_animate; 139 | bool m_update; 140 | unsigned int m_ratio; 141 | bool m_usedark; 142 | QString m_url; 143 | QString m_port; 144 | void readSettings(); 145 | QStringList m_categories; 146 | QHash m_categorieswithlocal; 147 | 148 | private slots: 149 | void packageProcessFinished(int code); 150 | void packageProcessStatus(const QString &status, const QString &pkg, 151 | int value, const QString &desc); 152 | void updateListUsingPackageManager(QList &list); 153 | QString getLanguagePackage(const QString &pkg) const; 154 | void writeSettings(const QString &key, const QVariant &value); 155 | void getSelfVersion(); 156 | 157 | signals: 158 | void processingFinished(); 159 | void processingFinishedWithError(const QString &output); 160 | void processingStatus(const QString &condition, int percent); 161 | void descriptionReceived(const QString &description); 162 | void surveychoiceChanged(); 163 | void versionChanged(); 164 | void surveyListReceived(const bool isform, const QString &title, 165 | const QString &question, const QStringList &choices, 166 | const unsigned int ×tamp, const bool pending); 167 | void surveyJoinSuccess(); 168 | void screenshotNotFound(); 169 | void fetchingAppListFinished(); 170 | void gatheringLocalDetailFinished(); 171 | void animateChanged(); 172 | void updateChanged(); 173 | void ratioChanged(); 174 | void usedarkChanged(); 175 | void correctingFinished(); 176 | void correctingFinishedWithError(const QString &errorString); 177 | void replyError(const QString &errorString); 178 | void detailsReceived(const QStringList &changeloglatest, const QString &changeloghistory, 179 | const unsigned int ×tamp, const QString ©right, 180 | const QString &description, 181 | const unsigned int &download, const QString &license, 182 | const QString &mmail, const QString &mname, const QStringList &screenshots, 183 | const QString §ion, const QString &website); 184 | void ratingDetailReceived(const double &average, 185 | const unsigned int &individual, 186 | const unsigned int &total, 187 | const QList &rates); 188 | void surveyDetailReceived(const unsigned int &count, const QString &reason, 189 | const QString &website, const QString &explanation); 190 | void homeReceived(const QString &ename, const QString &epname, const QString &ecat, const QString &eexec, const bool eins, 191 | const unsigned int &ecount, const double &erating, const QString &ever, const QString &esize, const bool enf, 192 | const QString &dname, const QString &dpname, const QString &dcat, const QString &dexec, const bool dins, 193 | const unsigned int &dcount, const double &drating, const QString &dver, const QString &dsize, const bool dnf, 194 | const QString &rname, const QString &rpname, const QString &rcat, const QString &rexec, const bool rins, 195 | const unsigned int &rcount, const double &rrating, const QString &rver, const QString &rsize, const bool rnf); 196 | void categorylistChanged(); 197 | 198 | public slots: 199 | void appDetailReceivedSlot(const ApplicationDetail &ad); 200 | void appListReceivedSlot(const QList &apps); 201 | void homeReceivedSlot(const QList &apps); 202 | void surveyListReceivedSlot(const bool isForm, const QString &title, 203 | const QString &question, const QString &mychoice, 204 | const QStringList &choices, const unsigned int ×tamp, 205 | const bool pending); 206 | void surveyJoinResultReceivedSlot(const QString &duty, const int &result); 207 | void correctingFinishedSlot(); 208 | }; 209 | 210 | #endif // HELPER_H 211 | -------------------------------------------------------------------------------- /ui/NavigationBar.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.7 2 | import QtQuick.Controls 2.0 3 | import QtQuick.Controls.Material 2.0 4 | //import QtGraphicalEffects 1.0 5 | import ps.condition 1.0 6 | 7 | Rectangle { 8 | id: navi 9 | width: navigationBarWidth 10 | height: parent.height 11 | z : 93 12 | color: "#fa464646" 13 | 14 | property alias currentIndex : menuListView.currentIndex 15 | property int categoryItemHeight: 30 16 | property int categoryItemListSpacing: 3 17 | property int menuItemHeight: 40 18 | property int menuItemListSpacing: 3 19 | 20 | 21 | property alias processOutput: processOutputLabel 22 | property alias packageName: processOutputLabel.packageName 23 | property alias condition: processOutputLabel.condition 24 | 25 | function categoriesReceived() { 26 | for (var i = 0; i < categories.length; i++) { 27 | categoryListModel.append({"name" : categories[i]}) 28 | } 29 | } 30 | 31 | ListModel { 32 | id: menuListModel 33 | } 34 | 35 | ListModel { 36 | id: categoryListModel 37 | } 38 | 39 | Component.onCompleted: { 40 | categoriesFilled.connect(categoriesReceived) 41 | var cnt = 0; 42 | var index = 1; 43 | for (var key in menuList) { 44 | index = (key === "home") ? cnt : 1 45 | menuListModel.append({"name" : key, "localname": menuList[key]}) 46 | cnt = cnt + 1 47 | } 48 | menuListModel.move(index,0,1) 49 | } 50 | 51 | Component { 52 | id: categoryItemDelegate 53 | Rectangle { 54 | id:categoryItemWrapper 55 | anchors.horizontalCenter: parent.horizontalCenter 56 | width: parent.width * 3 / 4 57 | height: categoryItemHeight 58 | color: categoryMa.containsMouse ? "#15ffffff" : "#00ffffff" 59 | radius: 2 60 | Image { 61 | id: categoryItemIcon 62 | asynchronous: true 63 | source: ((name === "all") ? "qrc:/images/" : (helper.getMainUrl() + "/files/categoryicons/")) + name + ".svg" 64 | fillMode: Image.PreserveAspectFit 65 | height: categoryItemHeight - anchors.topMargin * 2 66 | width: height 67 | sourceSize.width: width 68 | sourceSize.height: width 69 | smooth: true 70 | anchors { 71 | top: parent.top 72 | topMargin: 2 73 | left: parent.left 74 | leftMargin: width / 2 75 | } 76 | } 77 | 78 | Label { 79 | id: categoryItemLabel 80 | anchors { 81 | verticalCenter : categoryItemIcon.verticalCenter 82 | left: categoryItemIcon.right 83 | leftMargin: categoryItemIcon.width / 2 84 | right: parent.right 85 | rightMargin: 2 86 | } 87 | color: name === selectedCategory ? accentColor : "#E4E4E4" 88 | font.capitalization: Font.Capitalize 89 | text: name === "all" ? qsTr("all") :helper.getCategoryLocal(name) 90 | fontSizeMode: Text.HorizontalFit 91 | } 92 | 93 | MouseArea { 94 | id: categoryMa 95 | anchors.fill: parent 96 | hoverEnabled: true 97 | onClicked: { 98 | if(name === selectedCategory && applicationModel.getFilterString() !== "") { 99 | applicationModel.setFilterString(selectedCategory === "all" ? "" : name, false) 100 | } 101 | 102 | selectedCategory = name 103 | forceActiveFocus() 104 | } 105 | onPressed: { 106 | categoryItemLabel.scale = 0.95 107 | } 108 | onPressAndHold: { 109 | categoryItemLabel.scale = 0.95 110 | } 111 | onReleased: { 112 | categoryItemLabel.scale = 1 113 | } 114 | } 115 | } 116 | } 117 | 118 | Component { 119 | id: menuItemDelegate 120 | Item { 121 | id: menuItemWrapper 122 | anchors.horizontalCenter: parent.horizontalCenter 123 | width: navi.width 124 | height: menuItemHeight 125 | state: ((name === "categories") && expanded) ? "expanded" : "" 126 | 127 | 128 | Item { 129 | id: menuItem 130 | width: parent.width 131 | anchors.horizontalCenter: parent.horizontalCenter 132 | height: 40 133 | 134 | Rectangle { 135 | id: bgRect 136 | color: name === selectedMenu ? backgroundColor : "transparent" 137 | visible: true 138 | width: parent.width 139 | height: parent.height 140 | } 141 | 142 | Image { 143 | id: menuItemIcon 144 | asynchronous: true 145 | source: "qrc:/images/" + name + ((bgRect.color == "#f0f0f0") ? "-dark.svg" : ".svg") 146 | fillMode: Image.PreserveAspectFit 147 | height: 36 148 | width: height 149 | sourceSize.width: width 150 | sourceSize.height: width 151 | smooth: true 152 | anchors { 153 | top: parent.top 154 | topMargin: 2 155 | left: parent.left 156 | leftMargin: width * 3 / 4 157 | } 158 | } 159 | 160 | Label { 161 | id: menuItemLabel 162 | anchors { 163 | verticalCenter : menuItemIcon.verticalCenter 164 | left: menuItemIcon.right 165 | leftMargin: menuItemIcon.width / 2 166 | right: parent.right 167 | rightMargin: 2 168 | } 169 | color: name === selectedMenu ? accentColor : "#E4E4E4" 170 | font.bold: name === selectedMenu 171 | font.capitalization: Font.Capitalize 172 | text: localname 173 | fontSizeMode: Text.HorizontalFit 174 | } 175 | 176 | MouseArea { 177 | id: menuMa 178 | anchors.fill: parent 179 | onClicked: { 180 | forceActiveFocus() 181 | if(selectedMenu === "home" && name === "home" && stackView.depth > 1) { 182 | stackView.pop(null) 183 | } else { 184 | selectedMenu = name 185 | if(selectedMenu === "categories") { 186 | expanded = !expanded 187 | selectedCategory = "all" 188 | } else { 189 | expanded = false 190 | } 191 | } 192 | } 193 | onPressed: { 194 | menuItemLabel.scale = 0.95 195 | } 196 | onPressAndHold: { 197 | menuItemLabel.scale = 0.95 198 | } 199 | onReleased: { 200 | menuItemLabel.scale = 1 201 | } 202 | } 203 | } 204 | 205 | Item { 206 | id: subListWrapper 207 | anchors { 208 | top: menuItem.bottom 209 | topMargin: 6 210 | bottom: parent.bottom 211 | left: parent.left 212 | right: parent.right 213 | 214 | } 215 | 216 | ListView { 217 | id: categoryListView 218 | clip: true 219 | interactive: false 220 | cacheBuffer: (categoryItemHeight + 4) * categories.length 221 | spacing: categoryItemListSpacing 222 | anchors.fill: parent 223 | model: categoryListModel 224 | delegate: categoryItemDelegate 225 | } 226 | } 227 | 228 | states: [ 229 | State { 230 | name: "expanded" 231 | PropertyChanges { target: menuItemWrapper; height: menuItemHeight + categories.length * (categoryItemHeight + categoryItemListSpacing) + categoryItemListSpacing} 232 | } 233 | ] 234 | 235 | transitions: [ 236 | Transition { 237 | enabled: animate 238 | NumberAnimation { 239 | duration: 200 240 | properties: "height" //,width,anchors.rightMargin,anchors.topMargin,opacity,contentY" 241 | } 242 | } 243 | ] 244 | } 245 | } 246 | 247 | SearchBar { 248 | id: searchBar 249 | anchors { 250 | horizontalCenter: parent.horizontalCenter 251 | top: parent.top 252 | topMargin: 21 253 | } 254 | } 255 | 256 | ListView { 257 | id: menuListView 258 | anchors { 259 | horizontalCenter: parent.horizontalCenter 260 | top: searchBar.bottom 261 | topMargin: 21 262 | bottom: parent.bottom 263 | } 264 | 265 | delegate: menuItemDelegate 266 | model: menuListModel 267 | spacing: menuItemListSpacing 268 | } 269 | 270 | Item { 271 | id: userContainer 272 | width: parent.width 273 | height: width / 3 - 12 274 | anchors { 275 | horizontalCenter: parent.horizontalCenter 276 | bottom: polContainer.top 277 | bottomMargin: 3 278 | } 279 | 280 | Rectangle { 281 | id: account 282 | width: parent.width * 3 / 4 + 24 283 | height: parent.height 284 | color: "transparent" 285 | anchors { 286 | horizontalCenter: parent.horizontalCenter 287 | } 288 | 289 | MouseArea { 290 | id: accountMa 291 | anchors.fill: parent 292 | hoverEnabled: true 293 | cursorShape: Qt.WhatsThisCursor 294 | ToolTip.text: qsTr("This section is under development") 295 | ToolTip.delay: 500 296 | ToolTip.visible: containsMouse 297 | ToolTip.timeout: 5000 298 | } 299 | 300 | Image { 301 | id: accountImage 302 | height: parent.height - 12 303 | width: height 304 | enabled: false 305 | anchors { 306 | verticalCenter: parent.verticalCenter 307 | left: parent.left 308 | leftMargin: 3 309 | } 310 | sourceSize { 311 | width: width 312 | height: height 313 | } 314 | 315 | source: "image://application/avatar-default" 316 | } 317 | 318 | Label { 319 | id: accountNameLabel 320 | enabled: false 321 | width: parent.width - accountImage.width -6 322 | verticalAlignment: Text.AlignVCenter 323 | horizontalAlignment: Text.AlignHCenter 324 | font.pointSize: 11 325 | wrapMode: Text.WordWrap 326 | Material.foreground: secondaryTextColor 327 | anchors { 328 | verticalCenter: parent.verticalCenter 329 | left: accountImage.right 330 | leftMargin: 6 331 | } 332 | text: qsTr("Anonymus Account") 333 | } 334 | } 335 | 336 | } 337 | 338 | Item { 339 | id: polContainer 340 | width: parent.width 341 | height: 24 342 | anchors.bottom: parent.bottom 343 | MouseArea { 344 | anchors.fill: parent 345 | hoverEnabled: true 346 | onContainsMouseChanged: { 347 | if(containsMouse && isThereOnGoingProcess) { 348 | queueDialog.open() 349 | } 350 | } 351 | } 352 | 353 | Label { 354 | id: processOutputLabel 355 | property string packageName: "" 356 | property int condition: Condition.Idle 357 | anchors { 358 | centerIn: parent 359 | } 360 | opacity: 1.0 361 | fontSizeMode: Text.VerticalFit 362 | wrapMode: Text.WordWrap 363 | verticalAlignment: Text.AlignVCenter 364 | horizontalAlignment: Text.AlignHCenter 365 | font.capitalization: Font.Capitalize 366 | enabled: false 367 | text: "" 368 | 369 | onTextChanged: { 370 | opacity = 1.0 371 | } 372 | 373 | onConditionChanged: { 374 | if (condition === Condition.Idle) { 375 | processOutputLabel.text = "" 376 | } else if(condition === Condition.Installed || condition === Condition.Removed) { 377 | processOutputLabel.text = packageName + " " + qsTr("is") + " " + getConditionString(condition) 378 | } else { 379 | processOutputLabel.text = getConditionString(condition) + " " + packageName 380 | } 381 | } 382 | 383 | Behavior on opacity { 384 | enabled: animate 385 | NumberAnimation { 386 | easing.type: Easing.OutExpo 387 | duration: 200 388 | } 389 | } 390 | 391 | Timer { 392 | id: outputTimer 393 | interval: 8000 394 | repeat: true 395 | running: true 396 | onTriggered: { 397 | if(!isThereOnGoingProcess) { 398 | processOutputLabel.opacity = 0.0 399 | } 400 | } 401 | } 402 | } 403 | 404 | } 405 | } 406 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | pardus-store (0.3.1~beta4) unstable; urgency=medium 2 | 3 | * Handle ratio dynamically, remove it from settings 4 | 5 | -- Yunusemre Şentürk Wed, 06 Feb 2019 12:31:01 +0300 6 | 7 | pardus-store (0.3.1~beta3) unstable; urgency=medium 8 | 9 | * Fix not handling states when swtiched from home screen 10 | * Fix when applist not constructed app installed state does not change 11 | * Fix when home menu clicked doesnt return when stack depth is 2 12 | 13 | -- Yunusemre Şentürk Thu, 31 Jan 2019 13:20:53 +0300 14 | 15 | pardus-store (0.3.1~beta2) unstable; urgency=medium 16 | 17 | * Fix if app in the queue when switching from home page 18 | * Update home screen and survey when switched back to home 19 | * Fix progress bar background transparency on detail page 20 | 21 | -- Yunusemre Şentürk Wed, 30 Jan 2019 12:03:46 +0300 22 | 23 | pardus-store (0.3.1~beta1) unstable; urgency=medium 24 | 25 | * Bump version to 0.3.1~beta1 26 | * Make another role just for search. Closes: #11 27 | * Prepare survey form mechanism 28 | * Implement dynamic survey and make it functional. Closes: #7 29 | * Fix update bug on repeater in survey list 30 | * Add count down for custom surveys 31 | * Make switching to detail from home page possible. 32 | * Decrease font pointsize in survey detail app name 33 | 34 | -- Yunusemre Şentürk Tue, 29 Jan 2019 18:09:30 +0300 35 | 36 | pardus-store (0.3.0~beta4) unstable; urgency=medium 37 | 38 | * Fix label clip issue on Detail page action button 39 | * Clear images 40 | * Update README.md and screenshots 41 | * Fix latest changelog data clip issue 42 | * Put progress on images incase very low connection speed 43 | * Update docker file 44 | * Handle qml component network requests manually. Closes: #38 45 | * Make cache path defined before class definitions 46 | * Fix condition handling issues and bring back queue dialog 47 | 48 | -- Yunusemre Şentürk Mon, 21 Jan 2019 16:43:55 +0300 49 | 50 | pardus-store (0.3.0~beta3) unstable; urgency=medium 51 | 52 | * Fix long name clip issue on detail 53 | * Prepare backend for dynamic categories 54 | * Implement dynamic category handling and make it functional 55 | * Make main url configurable over config.ini 56 | 57 | -- Yunusemre Şentürk Thu, 17 Jan 2019 08:47:15 +0300 58 | 59 | pardus-store (0.3.0~beta2) unstable; urgency=medium 60 | 61 | * Fix delegate label clip issue on width bigger then 2 x height. Change minimum weight and height values. 62 | * Fix navigation problem when search does not match 63 | * Add delay on disclaimer shrink animation 64 | * Add progress status on Details page 65 | 66 | -- Yunusemre Şentürk Tue, 15 Jan 2019 13:25:25 +0300 67 | 68 | pardus-store (0.3.0~beta1) unstable; urgency=medium 69 | 70 | * Bump the version 0.3.0 71 | * Update Delegate visual design and remove common progressbar 72 | * Update settings for new delegate design column count 73 | * Make settings options highlighted for better navigation 74 | * Add account section on Navigation bar for future development as disabled 75 | * Fix gridview margins to adapt with new detail page 76 | * Define default colors in conf 77 | * Change application detail argument mechanism for new detail page 78 | * Change some static colors into global variable 79 | * Prepare banner for misc. details and rating 80 | * Prepare detail frontend for new backend api 81 | * Change handling application lists mechanism in backend 82 | * Make backend even faster when evaluating server reply 83 | * Change signal handling in details page and add open application mechanism as disabled for now 84 | * Implement rating system and make it functional 85 | * Fix several checking for MAC ID and handle app installed reply 86 | * Update Turkish translations 87 | * Handle statistics in helper and fix open app backend 88 | * Implement open apps externally and make it functional 89 | * Add tooltip on links section and Make app banner name pretty 90 | * Prepare backend for changelog frontend 91 | * Take scale action in menu over clicks in order to help navigation 92 | * Finilize changelog detail frontend 93 | * Add copyright exemination mechanism in detail 94 | * Add scrollbar into exemine popup 95 | * Change Home screen for dynamic data 96 | * Fix parsing issue on details 97 | * Fix datetime displaying wrong date 98 | * Prepare review&rating frontend 99 | * Refactor whole color related variables and Add Light theme functionality. Closes: #26 100 | * Make default theme dark 101 | * Fix delegate elevation problem 102 | * Make home screen backend and frontend functional 103 | * Disable survey for the next dynamic survey commit 104 | * Update main URL 105 | * Update translation 106 | 107 | -- Yunusemre Şentürk Mon, 14 Jan 2019 17:49:52 +0300 108 | 109 | pardus-store (0.2.1~beta4) unstable; urgency=medium 110 | 111 | * Use domain instead of static IP 112 | * Fix Survey application detail oversized in frame 113 | * Fix icons rendering issues 114 | 115 | -- Yunusemre Şentürk Wed, 05 Dec 2018 15:17:18 +0300 116 | 117 | pardus-store (0.2.1~beta3) unstable; urgency=medium 118 | 119 | * Change icon theme dependency 120 | 121 | -- Yunusemre Şentürk Wed, 05 Dec 2018 12:11:11 +0300 122 | 123 | pardus-store (0.2.1~beta2) unstable; urgency=medium 124 | 125 | * Re arrange welcome text anchors 126 | 127 | -- Yunusemre Şentürk Mon, 27 Aug 2018 10:50:16 +0300 128 | 129 | pardus-store (0.2.1~beta1) unstable; urgency=medium 130 | 131 | [ Gökhan Karabulut ] 132 | * Add travis-ci 133 | * Remove trailing new lines in Dockerfile 134 | 135 | [ Yunusemre Şentürk ] 136 | * Update travis url in README.md 137 | * Update README.md and add screenshots 138 | 139 | [ Emin Fedar ] 140 | * HighDPIScaling Disabled edildi. 141 | 142 | [ Yunusemre Şentürk ] 143 | * Fix image load failure on initialisation of new Quick Look survey stack. Closes: #21 144 | 145 | -- Yunusemre Şentürk Wed, 22 Aug 2018 11:39:16 +0300 146 | 147 | pardus-store (0.2.0~beta5) unstable; urgency=medium 148 | 149 | * Make survey applications detail discoverable 150 | 151 | -- Yunusemre Şentürk Tue, 07 Aug 2018 12:06:17 +0300 152 | 153 | pardus-store (0.2.0~beta4) unstable; urgency=medium 154 | 155 | * Fix navigation problem after selecting from Home screen 156 | 157 | -- Yunusemre Şentürk Mon, 06 Aug 2018 14:39:22 +0300 158 | 159 | pardus-store (0.2.0~beta3) unstable; urgency=medium 160 | 161 | * Remove CategoryDelegate.qml file and fix config issues coused by upgrading 162 | 163 | -- Yunusemre Şentürk Mon, 06 Aug 2018 14:12:22 +0300 164 | 165 | pardus-store (0.2.0~beta2) unstable; urgency=medium 166 | 167 | * Make home screen banner stretchable 168 | * Fix position of the popup screenshot detail 169 | * Move searchbar vertically center of the top gap 170 | 171 | -- Yunusemre Şentürk Tue, 31 Jul 2018 18:32:25 +0800 172 | 173 | pardus-store (0.2.0~beta1) unstable; urgency=medium 174 | 175 | [ Yunusemre Şentürk ] 176 | * Bump the version to 0.2.0~beta1 177 | 178 | [ Gökhan Gurbetoğlu ] 179 | * Added description and version information 180 | * Added description and version information 181 | * Create LICENSE - GNU GPL v3.0 182 | 183 | [ Yunusemre Şentürk ] 184 | * Update README.md 185 | * Prepare ui for static and accordion navigation bar 186 | * Start implementing new menu style 187 | * Fix navigation for new static navigation bar 188 | * Move package installation status bar to navigation area 189 | 190 | [ Hikmet Baş ] 191 | * Redesign and integrate search bar 192 | 193 | [ Yunusemre Şentürk ] 194 | * Adjust cards and reinsert back button only for detail, update translation 195 | 196 | -- Yunusemre Şentürk Tue, 31 Jul 2018 15:41:38 +0800 197 | 198 | pardus-store (0.1.1~beta2) unstable; urgency=medium 199 | 200 | * Fix syntax error 201 | 202 | -- Yunusemre Şentürk Tue, 03 Jul 2018 10:30:22 +0300 203 | 204 | pardus-store (0.1.1~beta1) unstable; urgency=medium 205 | 206 | * Fix settings view overrides the navigation bar on z axis 207 | 208 | -- Yunusemre Şentürk Tue, 03 Jul 2018 09:11:26 +0300 209 | 210 | pardus-store (0.1.0) unstable; urgency=medium 211 | 212 | * Bump version to 0.1.0 213 | * Prepare frontend for the sources list correction 214 | * Finish up backend file io operations for sources list correction 215 | 216 | -- Yunusemre Şentürk Tue, 26 Jun 2018 16:15:32 +0300 217 | 218 | pardus-store (0.0.24~alpha) unstable; urgency=medium 219 | 220 | * Fix reaching non existing indexes cousing seg fault 221 | 222 | -- Yunusemre Şentürk Sat, 23 Jun 2018 03:03:25 +0300 223 | 224 | pardus-store (0.0.23~alpha) unstable; urgency=medium 225 | 226 | * Fix variable confusion on app model cousing back btn miss behave 227 | 228 | -- Yunusemre Şentürk Tue, 19 Jun 2018 13:19:42 +0300 229 | 230 | pardus-store (0.0.22~alpha) unstable; urgency=medium 231 | 232 | * Make self version live in Home screen 233 | 234 | -- Yunusemre Şentürk Tue, 19 Jun 2018 12:45:30 +0300 235 | 236 | pardus-store (0.0.21~alpha) unstable; urgency=medium 237 | 238 | * Make application list view configurable and add download size for more readability 239 | 240 | -- Yunusemre Şentürk Tue, 19 Jun 2018 11:49:11 +0300 241 | 242 | pardus-store (0.0.20~alpha) unstable; urgency=medium 243 | 244 | * Update Turkish translations 245 | 246 | -- Yunusemre Şentürk Thu, 14 Jun 2018 11:59:32 +0300 247 | 248 | pardus-store (0.0.19~alpha) unstable; urgency=medium 249 | 250 | * Improve visual on application delegate installed badge 251 | * Update category text capitlization on App list pageview 252 | * Add global variable for animation disabling 253 | * Implement stackview to be able to disable animations on swipe 254 | * Adjust qml resources according to stackview 255 | * implement remove animation for gridview 256 | * Fix some visual bugs after stackview implementation 257 | * Fix some visual bugs 258 | 259 | -- Yunusemre Şentürk Thu, 14 Jun 2018 11:51:56 +0300 260 | 261 | pardus-store (0.0.18~alpha) unstable; urgency=medium 262 | 263 | * Prepare a maximize button and make changes for size changing 264 | * Adjust navigation and search bar respecting size changes 265 | * Update category icons for HiDpi resolutions 266 | 267 | -- Yunusemre Şentürk Mon, 21 May 2018 14:35:15 +0300 268 | 269 | pardus-store (0.0.17~alpha) unstable; urgency=medium 270 | 271 | * Update screenshot preview popup and make it more sharper 272 | 273 | -- Yunusemre Şentürk Fri, 18 May 2018 16:46:41 +0300 274 | 275 | pardus-store (0.0.16~alpha) unstable; urgency=medium 276 | 277 | * Add pardus otf and update welcome screens 278 | 279 | -- Yunusemre Şentürk Fri, 18 May 2018 15:18:35 +0300 280 | 281 | pardus-store (0.0.15~alpha) unstable; urgency=medium 282 | 283 | * Update Home screen and suggested application mechanism 284 | 285 | -- Yunusemre Şentürk Thu, 17 May 2018 15:29:00 +0300 286 | 287 | pardus-store (0.0.14~alpha) unstable; urgency=medium 288 | 289 | * Remove test.qml 290 | * Correct the pointsize ratio in circular progressbar 291 | * Make some application names look pretty 292 | 293 | -- Yunusemre Şentürk Wed, 16 May 2018 14:15:10 +0300 294 | 295 | pardus-store (0.0.13~alpha) unstable; urgency=medium 296 | 297 | * Update translations 298 | 299 | -- Yunusemre Şentürk Tue, 15 May 2018 14:30:18 +0300 300 | 301 | pardus-store (0.0.12~alpha) unstable; urgency=medium 302 | 303 | [ Yunusemre Şentürk ] 304 | * Fix process button enability not changed when process starts 305 | 306 | [ Cihangir Akturk ] 307 | * Add mechanism for tracking progress 308 | 309 | [ Yunusemre Şentürk ] 310 | * Add circular progressbar for processing package 311 | * Implement dpkg process fd for tracking package process. Closes: #12 312 | * Fix process button installed condition in detail 313 | 314 | -- Yunusemre Şentürk Tue, 15 May 2018 12:57:17 +0300 315 | 316 | pardus-store (0.0.11~alpha) unstable; urgency=medium 317 | 318 | * Update splash and applciation icon 319 | * Change StatusRole name to InstalledRole and qml side as "installed" 320 | * Remove debug outputs related proxy 321 | * Fix button disabled after certain application process finished in Detail 322 | * Fix searchbar text field white space condition 323 | 324 | -- Yunusemre Şentürk Fri, 11 May 2018 11:49:14 +0300 325 | 326 | pardus-store (0.0.10~alpha) unstable; urgency=medium 327 | 328 | [ Yusuf Düzgün ] 329 | * Use system proxy if exists 330 | 331 | [ Yunusemre Şentürk ] 332 | * Update gaining root privilege mechanism and remove gksu 333 | 334 | -- Yunusemre Şentürk Thu, 10 May 2018 11:55:04 +0300 335 | 336 | pardus-store (0.0.9~alpha) unstable; urgency=medium 337 | 338 | * Fix survey button apprereance 339 | * Break the loop when we find the first MAC address 340 | * Add category role to search filter roles when using searchbar 341 | * Make language packages installable if exists 342 | * Reverse changes abour search roles 343 | * Add settings pane and update backButton visibility statements 344 | * Update translations 345 | 346 | -- Yunusemre Şentürk Tue, 08 May 2018 14:05:37 +0300 347 | 348 | pardus-store (0.0.8~alpha) unstable; urgency=medium 349 | 350 | [ Hikmet Baş ] 351 | * Fix welcome text offset 352 | 353 | [ Yunusemre Şentürk ] 354 | * Add API backend handler for survey 355 | * Update bindings against survey backend 356 | * Update translations 357 | 358 | -- Yunusemre Şentürk Fri, 04 May 2018 14:54:34 +0300 359 | 360 | pardus-store (0.0.7~alpha) unstable; urgency=medium 361 | 362 | * Change banner text and image source address 363 | * Update Translations 364 | 365 | -- Yunusemre Şentürk Thu, 03 May 2018 13:56:20 +0300 366 | 367 | pardus-store (0.0.6~alpha) unstable; urgency=medium 368 | 369 | * Fix error coming from image provider class 370 | * Update reading icon measures 371 | * Update some static visual adjusments to dynamic 372 | * Add missing translation in application detail 373 | * Fix the uncliped area bottom of queue dialog 374 | * Add default icon theme to recommends 375 | 376 | -- Yunusemre Şentürk Thu, 03 May 2018 11:41:09 +0300 377 | 378 | pardus-store (0.0.5~alpha) unstable; urgency=medium 379 | 380 | * Add confirmation dialog at removal. Closes: #4 381 | * Fix closing prevention from outside and seperation of confirmation dialog callbacks detail between delegate 382 | * Use QSharedMemory for signle instance running. Closes: #5 383 | * Use seperation of concern on dialogs and components 384 | * Update Turkish translations 385 | * Unbind model inqueue and qml inline property. Closes: #10 386 | * Take care of the delegates in quque repeater component. Closes: #9 387 | 388 | -- Yunusemre Şentürk Wed, 02 May 2018 16:29:53 +0300 389 | 390 | pardus-store (0.0.4~alpha) unstable; urgency=medium 391 | 392 | * Change API url 393 | 394 | -- Yunusemre Şentürk Mon, 30 Apr 2018 10:23:33 +0300 395 | 396 | pardus-store (0.0.3) unstable; urgency=medium 397 | 398 | [ Hikmet Baş ] 399 | * Fixed popupImage and added flickable area for description 400 | * Fixed category unchanged when back button clicked 401 | 402 | -- Yunusemre Şentürk Fri, 27 Apr 2018 16:52:40 +0300 403 | 404 | pardus-store (0.0.2) unstable; urgency=medium 405 | 406 | * Add post inst for 32-bit systems 407 | * add gbp.conf for clean build 408 | 409 | -- Yunusemre Şentürk Fri, 27 Apr 2018 12:05:06 +0300 410 | 411 | pardus-store (0.0.1) unstable; urgency=medium 412 | 413 | * Initial release. 414 | 415 | -- Yunusemre Şentürk Fri, 27 Apr 2018 11:27:33 +0300 416 | -------------------------------------------------------------------------------- /src/helper.cpp: -------------------------------------------------------------------------------- 1 | #include "helper.h" 2 | #include "application.h" 3 | #include "applicationdetail.h" 4 | #include "filehandler.h" 5 | #include "packagehandler.h" 6 | #include "networkhandler.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define CONFIG_PATH "/usr/share/pardus/pardus-store/config.ini" 14 | 15 | Helper::Helper(QObject *parent) : QObject(parent), 16 | p(false), m_surveychoice(""), v("beta"), m_corrected(false), 17 | m_erroronreply(false), m_detailsopened(false), 18 | m_rating(0), m_homeloaded(true) 19 | { 20 | s = new QSettings(CONFIG_PATH, QSettings::IniFormat); 21 | readSettings(); 22 | 23 | nh = new NetworkHandler(url(),port(),10000,this); 24 | fh = new FileHandler(this); 25 | ph = new PackageHandler(this); 26 | 27 | connect(ph,SIGNAL(finished(int)),this,SLOT(packageProcessFinished(int))); 28 | connect(ph,SIGNAL(dpkgProgressStatus(QString,QString,int,QString)),this,SLOT(packageProcessStatus(QString,QString,int,QString))); 29 | connect(nh,SIGNAL(appListReceived(QList)),this,SLOT(appListReceivedSlot(QList))); 30 | connect(nh,SIGNAL(appDetailsReceived(ApplicationDetail)),this,SLOT(appDetailReceivedSlot(ApplicationDetail))); 31 | connect(nh,SIGNAL(replyError(QString)),this,SIGNAL(replyError(QString))); 32 | connect(nh,SIGNAL(appRatingReceived(double,uint,uint,QList)),this,SIGNAL(ratingDetailReceived(double,uint,uint,QList))); 33 | connect(nh,SIGNAL(homeAppListReceived(QList)),this, SLOT(homeReceivedSlot(QList))); 34 | connect(nh,SIGNAL(surveyListReceived(bool,QString,QString,QString,QStringList,uint,bool)), 35 | this,SLOT(surveyListReceivedSlot(bool,QString,QString,QString,QStringList,uint,bool))); 36 | connect(nh,SIGNAL(surveyJoinResultReceived(QString,int)),this,SLOT(surveyJoinResultReceivedSlot(QString,int))); 37 | connect(nh,SIGNAL(surveyDetailReceived(uint,QString,QString,QString)),this,SIGNAL(surveyDetailReceived(uint,QString,QString,QString))); 38 | connect(fh,SIGNAL(correctingSourcesFinished()),this,SLOT(correctingFinishedSlot())); 39 | connect(fh,SIGNAL(correctingSourcesFinishedWithError(QString)),this,SIGNAL(correctingFinishedWithError(QString))); 40 | } 41 | 42 | Helper::~Helper() 43 | { 44 | writeSettings("url",m_url); 45 | writeSettings("port",m_port); 46 | } 47 | 48 | bool Helper::animate() const 49 | { 50 | return m_animate; 51 | } 52 | 53 | void Helper::setAnimate(bool a) 54 | { 55 | if(a != m_animate) { 56 | m_animate = a; 57 | writeSettings("animate", m_animate); 58 | emit animateChanged(); 59 | } 60 | } 61 | 62 | bool Helper::update() const 63 | { 64 | return m_update; 65 | } 66 | 67 | void Helper::setUpdate(bool u) 68 | { 69 | if(u != m_update) { 70 | m_update = u; 71 | writeSettings("update", m_update); 72 | emit updateChanged(); 73 | } 74 | } 75 | 76 | unsigned int Helper::ratio() const 77 | { 78 | return m_ratio; 79 | } 80 | 81 | void Helper::setRatio(const unsigned int &r) 82 | { 83 | if(r != m_ratio ) { 84 | if(r >= 4) { 85 | m_ratio = 3; 86 | } else if (r <= 1) { 87 | m_ratio = 2; 88 | } else { 89 | m_ratio = r; 90 | } 91 | writeSettings("ratio", m_ratio); 92 | emit ratioChanged(); 93 | } 94 | } 95 | 96 | bool Helper::usedark() const 97 | { 98 | return m_usedark; 99 | } 100 | 101 | void Helper::setUsedark(bool d) 102 | { 103 | if( d != m_usedark) { 104 | m_usedark = d; 105 | writeSettings("dark-theme", m_usedark); 106 | emit usedarkChanged(); 107 | } 108 | } 109 | 110 | QString Helper::url() const 111 | { 112 | return m_url; 113 | } 114 | 115 | QString Helper::port() const 116 | { 117 | return m_port; 118 | } 119 | 120 | void Helper::setUrl(const QString &u) 121 | { 122 | if(m_url != u) { 123 | m_url = u; 124 | writeSettings("url",m_url); 125 | } 126 | } 127 | 128 | void Helper::setPort(const QString &p) 129 | { 130 | if(m_port != p) { 131 | m_port = p; 132 | writeSettings("port",m_port); 133 | } 134 | } 135 | 136 | void Helper::readSettings() 137 | { 138 | setAnimate(s->value("animate", true).toBool()); 139 | setUpdate(s->value("update", true).toBool()); 140 | setRatio(s->value("ratio", 3).toUInt()); 141 | setUsedark(s->value("dark-theme", true).toBool()); 142 | setUrl(s->value("url","http://store.pardus.org.tr").toString()); 143 | setPort(s->value("port","5000").toString()); 144 | } 145 | 146 | void Helper::writeSettings(const QString &key, const QVariant &value) 147 | { 148 | s->setValue(key,value); 149 | } 150 | 151 | bool Helper::processing() const 152 | { 153 | return p; 154 | } 155 | 156 | QString Helper::surveychoice() const 157 | { 158 | return m_surveychoice; 159 | } 160 | 161 | QString Helper::version() const 162 | { 163 | return v; 164 | } 165 | 166 | bool Helper::corrected() const 167 | { 168 | return m_corrected; 169 | } 170 | 171 | bool Helper::erroronreply() const 172 | { 173 | return m_erroronreply; 174 | } 175 | 176 | bool Helper::detailsopened() const 177 | { 178 | return m_detailsopened; 179 | } 180 | 181 | void Helper::setDetailsopened(bool d) 182 | { 183 | m_detailsopened = d; 184 | } 185 | 186 | unsigned int Helper::rating() 187 | { 188 | return m_rating; 189 | } 190 | 191 | bool Helper::homeLoaded() 192 | { 193 | return m_homeloaded; 194 | } 195 | 196 | QStringList Helper::categorylist() const 197 | { 198 | return m_categories; 199 | } 200 | 201 | void Helper::fillTheList() 202 | { 203 | for(int i = 0; i < m_fakelist.size(); i++) { 204 | lc.l->addData(m_fakelist.at(i)); 205 | } 206 | getHomeScreenDetails(); 207 | } 208 | 209 | void Helper::updateCache() 210 | { 211 | ph->updateCache(); 212 | } 213 | 214 | void Helper::install(const QString &pkg) 215 | { 216 | p = true; 217 | QString package = getLanguagePackage(pkg); 218 | if(package != "") { 219 | ph->install(package); 220 | } else { 221 | ph->install(pkg); 222 | } 223 | } 224 | 225 | void Helper::remove(const QString &pkg) 226 | { 227 | p = true; 228 | ph->remove(pkg); 229 | } 230 | 231 | bool Helper::terminate() 232 | { 233 | return ph->terminate(); 234 | } 235 | 236 | void Helper::getAppList() 237 | { 238 | nh->getApplicationList(); 239 | } 240 | 241 | void Helper::getAppDetails(const QString &pkg) 242 | { 243 | nh->getApplicationDetails(pkg); 244 | } 245 | 246 | void Helper::ratingControl(const QString &name, const unsigned int &rating) 247 | { 248 | nh->ratingControl(name,rating); 249 | } 250 | 251 | void Helper::getHomeScreenDetails() 252 | { 253 | nh->getHomeDetails(); 254 | } 255 | 256 | void Helper::surveyCheck() 257 | { 258 | nh->surveyCheck(); 259 | } 260 | 261 | void Helper::surveyJoin(const QString &option, const bool sendingForm, const QString &reason, const QString &website, const QString &mail, const QString &explanation) 262 | { 263 | nh->surveyJoin(option,sendingForm,reason,website,mail,explanation); 264 | } 265 | 266 | void Helper::getSurveyDetail(const QString &name) 267 | { 268 | nh->surveyDetail(name); 269 | } 270 | 271 | void Helper::systemNotify(const QString &pkg, const QString &title, const QString &content) 272 | { 273 | QProcess p; 274 | QStringList args; 275 | args << "-u" << "normal"; 276 | args << "-t" << "13000"; 277 | args << "-i" << pkg; 278 | args << title << content; 279 | 280 | QString command = "/usr/bin/notify-send"; 281 | p.execute(command, args); 282 | } 283 | 284 | QString Helper::getMainUrl() const 285 | { 286 | return nh->getMainUrl(); 287 | } 288 | 289 | void Helper::correctSourcesList() 290 | { 291 | fh->correctSources(); 292 | } 293 | 294 | void Helper::openUrl(const QString &url) 295 | { 296 | QProcess p1; 297 | QString user; 298 | QString out; 299 | QStringList args; 300 | p1.start("who"); 301 | p1.waitForFinished(-1); 302 | out = QString::fromLatin1(p1.readAllStandardOutput()); 303 | p1.close(); 304 | 305 | if(out.contains(":0")) { 306 | QProcess p; 307 | user = out.split(" ")[0]; 308 | args << "-u" << user << "--"; 309 | args << "xdg-open" << url; 310 | p.execute("sudo",args); 311 | } 312 | } 313 | 314 | void Helper::runCommand(const QString &cmd) 315 | { 316 | QProcess p1; 317 | QString user; 318 | QString out; 319 | QStringList args; 320 | p1.start("who"); 321 | p1.waitForFinished(-1); 322 | out = QString::fromLatin1(p1.readAllStandardOutput()); 323 | p1.close(); 324 | 325 | QString command = cmd; 326 | if(out.contains(":0")) { 327 | QProcess p; 328 | user = out.split(" ")[0]; 329 | args << "-i"; 330 | args << "-u" << user << "--"; 331 | args << command.split(" "); 332 | p.startDetached("sudo", args); 333 | } 334 | } 335 | 336 | void Helper::sendStatistics(const QString &appname) 337 | { 338 | nh->sendApplicationInstalled(appname); 339 | } 340 | 341 | void Helper::updatePackageInstalledStatus(const QString &pkg, const bool s) 342 | { 343 | int index = 0; 344 | for(int i = 0; i< m_fakelist.length(); i++) { 345 | if(m_fakelist.at(i).name() == pkg) { 346 | index = i; 347 | } 348 | } 349 | if(!lc.l->setInstallStatusAtIndex(index,s)) { 350 | qDebug() << "Something went wrong while updating package installed status"; 351 | } 352 | } 353 | 354 | QString Helper::getCategoryLocal(const QString &c) const 355 | { 356 | return m_categorieswithlocal.value(c); 357 | } 358 | 359 | void Helper::packageProcessFinished(int code) 360 | { 361 | if(code == 0) { 362 | emit processingFinished(); 363 | } else { 364 | emit processingFinishedWithError(QString::fromLatin1(ph->getError())); 365 | } 366 | 367 | p = false; 368 | } 369 | 370 | void Helper::packageProcessStatus(const QString &status, const QString &pkg, int value, const QString &desc) 371 | { 372 | Q_UNUSED(pkg); 373 | Q_UNUSED(desc); 374 | emit processingStatus(status, value); 375 | } 376 | 377 | void Helper:: updateListUsingPackageManager(QList &list) 378 | { 379 | QMap sizeList; 380 | QString apps; 381 | for(int i = 0; i < list.size(); i++) { 382 | sizeList.insert(list.at(i).name(),""); 383 | apps += list.at(i).name(); 384 | if (i != (list.size() - 1)) { 385 | apps += " "; 386 | } 387 | } 388 | 389 | QStringList output = ph->getPolicy(apps).split(QRegExp("\n|\r\n|\r")); 390 | QStringList showOutput = ph->getShow(apps).split(QRegExp("\n|\r\n|\r")); 391 | 392 | QString name = ""; 393 | bool nameChanged = false; 394 | foreach (QString ln, showOutput) { 395 | if(ln.contains(QRegExp("^Package"))) { 396 | if(ln.mid(9) != name) { 397 | name = ln.mid(9); 398 | nameChanged = true; 399 | } else { 400 | nameChanged = false; 401 | } 402 | } else if(ln.contains(QRegExp("^Size"))) { 403 | if(nameChanged) { 404 | double size = ln.mid(6).toDouble() / 1024.0; 405 | 406 | if(size > 1024) { 407 | size = size / 1024.0; 408 | ln = QString(QString::number(size,'f',1) + " MB"); 409 | } else { 410 | ln = QString(QString::number(size,'f',1) + " KB"); 411 | } 412 | sizeList.insert(name,ln); 413 | } 414 | } 415 | } 416 | 417 | 418 | int ix = 0; 419 | QString checkInstalled; 420 | 421 | for(int i = 0; i< list.size(); i++) { 422 | ix = output.indexOf(QRegExp(list[i].name() + QString("*.*"))); 423 | checkInstalled = output.at(ix + 1).split(" ").last(); 424 | if (checkInstalled.contains("none")) { 425 | list[i].setInstalled(false); 426 | list[i].setState("get"); 427 | } else { 428 | list[i].setInstalled(true); 429 | list[i].setState("installed"); 430 | } 431 | list[i].setVersion(output.at(ix + 2).split(" ").last()); 432 | list[i].setDownloadsize(sizeList.value(list[i].name())); 433 | } 434 | } 435 | 436 | QString Helper::getLanguagePackage(const QString &pkg) const 437 | { 438 | QStringList l = ph->getSearch(pkg).split("\n"); 439 | QString lang = QLocale::system().name(); 440 | QString langMajor = lang.split("_")[0]; 441 | QString langMinor = lang.split("_")[1]; 442 | 443 | QStringList pl; 444 | QString result = ""; 445 | 446 | foreach (QString str, l) { 447 | if(str.contains("language")) { 448 | pl.append(str.split(" - ")[0]); 449 | } 450 | } 451 | if(pl.size() > 1) { 452 | foreach (QString s, pl) { 453 | if(langMajor.toLower() == lang.toLower()) { 454 | if (s.contains(langMajor, Qt::CaseInsensitive)) { 455 | result = s; 456 | } 457 | } else { 458 | if (s.contains(langMajor, Qt::CaseInsensitive) && 459 | s.contains(langMinor, Qt::CaseInsensitive)) { 460 | result = s; 461 | } 462 | } 463 | } 464 | } else if(pl.size() == 1) { 465 | result = pl[0]; 466 | } 467 | 468 | return result; 469 | } 470 | 471 | void Helper::appDetailReceivedSlot(const ApplicationDetail &ad) 472 | { 473 | emit detailsReceived(ad.changelogLatest(), ad.changelogHistory(), ad.changelogTimestamp(), 474 | ad.copyright(), ad.description(),ad.download(),ad.license(), 475 | ad.maintainerMail(),ad.maintainerName(),ad.screenshots(), 476 | ad.section(),ad.website()); 477 | emit descriptionReceived(ad.description()); 478 | } 479 | 480 | void Helper::getSelfVersion() 481 | { 482 | QStringList output = ph->getPolicy("pardus-store").split(QRegExp("\n|\r\n|\r")); 483 | int ix = output.indexOf(QRegExp("pardus-store" + QString("*.*"))); 484 | QString installed = output.at(ix + 1).split(" ").last(); 485 | if(!installed.contains("none")) { 486 | v = installed; 487 | emit versionChanged(); 488 | } 489 | } 490 | 491 | void Helper::appListReceivedSlot(const QList &apps) 492 | { 493 | m_fakelist = apps; 494 | for(int i = 0; i< m_fakelist.length(); i++) { 495 | if(!m_categories.contains(m_fakelist[i].category()) && m_fakelist[i].category() != "") { 496 | m_categories.append(m_fakelist[i].category()); 497 | m_categorieswithlocal.insert(m_fakelist[i].category(),m_fakelist[i].categoryLocal()); 498 | } 499 | } 500 | m_categories.sort(); 501 | if(m_categories.contains("others")) { 502 | m_categories.removeAt(m_categories.indexOf("others")); 503 | m_categories.append("others"); 504 | } 505 | emit categorylistChanged(); 506 | updateListUsingPackageManager(m_fakelist); 507 | emit fetchingAppListFinished(); 508 | getSelfVersion(); 509 | fillTheList(); 510 | } 511 | 512 | void Helper::homeReceivedSlot(const QList &apps) 513 | { 514 | m_homelist = apps; 515 | updateListUsingPackageManager(m_homelist); 516 | emit homeReceived(m_homelist[0].name(), m_homelist[0].prettyname(), m_homelist[0].category(), m_homelist[0].exec(), 517 | m_homelist[0].installed(), m_homelist[0].downloadcount(), m_homelist[0].rating(), m_homelist[0].version(), 518 | m_homelist[0].downloadsize(),m_homelist[0].nonfree(), 519 | m_homelist[1].name(), m_homelist[1].prettyname(), m_homelist[1].category(), m_homelist[1].exec(), 520 | m_homelist[1].installed(), m_homelist[1].downloadcount(), m_homelist[1].rating(), m_homelist[1].version(), 521 | m_homelist[1].downloadsize(), m_homelist[1].nonfree(), 522 | m_homelist[2].name(), m_homelist[2].prettyname(), m_homelist[2].category(), m_homelist[2].exec(), 523 | m_homelist[2].installed(), m_homelist[2].downloadcount(), m_homelist[2].rating(), m_homelist[2].version(), 524 | m_homelist[2].downloadsize(), m_homelist[2].nonfree()); 525 | emit gatheringLocalDetailFinished(); 526 | } 527 | 528 | void Helper::surveyListReceivedSlot(const bool isForm, const QString &title, 529 | const QString &question, const QString &mychoice, 530 | const QStringList &choices, const unsigned int ×tamp, 531 | const bool pending) 532 | { 533 | m_surveychoice = mychoice; 534 | emit surveychoiceChanged(); 535 | emit surveyListReceived(isForm,title,question,choices,timestamp,pending); 536 | } 537 | 538 | void Helper::surveyJoinResultReceivedSlot(const QString &duty, const int &result) 539 | { 540 | if (result == 1) { 541 | emit surveyJoinSuccess(); 542 | } else { 543 | qDebug() << "Survey join result is " << result << " duty is " << duty; 544 | } 545 | } 546 | 547 | void Helper::correctingFinishedSlot() 548 | { 549 | m_corrected = true; 550 | emit correctingFinished(); 551 | } 552 | --------------------------------------------------------------------------------