diff --git a/res/styles/device-list.qss b/res/styles/device-list.qss
new file mode 100644
index 0000000..045f80e
--- /dev/null
+++ b/res/styles/device-list.qss
@@ -0,0 +1,17 @@
+QListView {
+ outline: 0;
+ background-color: #FAFAFA;
+}
+
+QListView::item{
+ background-color: #E6E6E6;
+}
+
+QListView::item:hover{
+ background-color: #D6D6D6;
+}
+
+QListView::item:active:selected{
+ color: black;
+ background-color: #C1C1C1;
+}
\ No newline at end of file
diff --git a/res/styles/file-list.qss b/res/styles/file-list.qss
new file mode 100644
index 0000000..e1f4873
--- /dev/null
+++ b/res/styles/file-list.qss
@@ -0,0 +1,22 @@
+QListView {
+ outline: 0;
+ background-color: #FAFAFA;
+}
+
+QListView::item{
+ background-color: #E6E6E6;
+}
+
+QListView::item:hover{
+ background-color: #D6D6D6;
+}
+
+QListView::item:active:selected{
+ color: black;
+ background-color: #C1C1C1;
+ border: 1px solid #666666;
+}
+
+QListView::item:active:!selected{
+ border: 1px solid #AAAAAA;
+}
\ No newline at end of file
diff --git a/res/styles/window.qss b/res/styles/window.qss
index e38a9c8..309bf96 100644
--- a/res/styles/window.qss
+++ b/res/styles/window.qss
@@ -1,3 +1,3 @@
QWidget {
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+ font-family: url("-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif");
}
\ No newline at end of file
diff --git a/src/app.py b/src/app.py
index d18de98..62304ca 100644
--- a/src/app.py
+++ b/src/app.py
@@ -21,6 +21,7 @@
from core.configurations import Resources
from core.main import Adb
from gui.window import MainWindow
+from helpers.tools import read_string_from_file
if __name__ == '__main__':
adb = Adb()
@@ -30,7 +31,7 @@
app = QApplication(sys.argv)
window = MainWindow()
- window.setStyleSheet(Resources.read_string_from_file(Resources.style_window))
+ window.setStyleSheet(read_string_from_file(Resources.style_window))
window.show()
sys.exit(app.exec_())
diff --git a/src/core/configurations.py b/src/core/configurations.py
index 5825c85..319893f 100644
--- a/src/core/configurations.py
+++ b/src/core/configurations.py
@@ -18,19 +18,14 @@
import pathlib
import platform
-from PyQt5.QtCore import QFile, QIODevice, QTextStream
-
from data.models import Device
from helpers.tools import Singleton
class Application:
- __version__ = '1.1.0'
+ __version__ = '1.2.0'
__metaclass__ = Singleton
- def __init__(self):
- print(Application.NOTICE)
-
NOTICE = f"""\033[0;32m
ADB File Explorer v{__version__} Copyright (C) 2022 Azat Aldeshov
Platform {platform.platform()}
@@ -71,6 +66,8 @@ class Resources:
path = os.path.join(Application.PATH, 'res')
style_window = os.path.join(path, 'styles', 'window.qss')
+ style_file_list = os.path.join(path, 'styles', 'file-list.qss')
+ style_device_list = os.path.join(path, 'styles', 'device-list.qss')
style_notification_button = os.path.join(path, 'styles', 'notification-button.qss')
icon_logo = os.path.join(path, 'icons', 'logo.svg')
@@ -93,12 +90,3 @@ class Resources:
icon_folder_create = os.path.join(path, 'icons', 'files', 'actions', 'folder_create.svg')
anim_loading = os.path.join(path, 'anim', 'loading.gif')
-
- @staticmethod
- def read_string_from_file(path: str):
- file = QFile(path)
- if file.open(QIODevice.ReadOnly | QIODevice.Text):
- text = QTextStream(file).readAll()
- file.close()
- return text
- return ''
diff --git a/src/gui/abstract/__init__.py b/src/gui/abstract/__init__.py
deleted file mode 100644
index 8449e1e..0000000
--- a/src/gui/abstract/__init__.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# ADB File Explorer `tool`
-# Copyright (C) 2022 Azat Aldeshov azata1919@gmail.com
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
diff --git a/src/gui/abstract/base.py b/src/gui/abstract/base.py
deleted file mode 100644
index a8ee683..0000000
--- a/src/gui/abstract/base.py
+++ /dev/null
@@ -1,205 +0,0 @@
-# ADB File Explorer `tool`
-# Copyright (C) 2022 Azat Aldeshov azata1919@gmail.com
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-from PyQt5 import QtCore, QtGui
-from PyQt5.QtCore import Qt, QSize
-from PyQt5.QtGui import QPaintEvent, QPainter, QPixmap, QMovie
-from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QStyleOption, QStyle, QSizePolicy, QVBoxLayout, QGridLayout, \
- QLineEdit
-
-from core.configurations import Resources
-
-
-class BaseIconWidget(QLabel):
- def __init__(self, path, width=32, height=32, context: QWidget = None):
- super(BaseIconWidget, self).__init__()
- self.setParent(context)
- self.pixmap = QPixmap(path)
- self.pixmap = self.pixmap.scaled(width, height, Qt.KeepAspectRatio)
- self.setPixmap(self.pixmap)
-
-
-class BaseListHeaderWidget(QWidget):
- def __init__(self):
- super().__init__()
- self.layout = QHBoxLayout()
- self.layout.setContentsMargins(0, 0, 0, 0)
- self.setLayout(self.layout)
-
- @staticmethod
- def property(label, **kwargs):
- return BaseListItemWidget.property(
- label,
- font_style=kwargs.get("font_style"),
- alignment=kwargs.get("alignment"),
- width_policy=kwargs.get("width_policy"),
- height_policy=kwargs.get("height_policy"),
- stretch=kwargs.get("stretch")
- )
-
-
-class BaseListItemWidget(QWidget):
- def __init__(self, parent=None):
- super().__init__(parent)
- self.setMinimumHeight(40)
- self.setObjectName("item")
- self.installEventFilter(self)
- self.setStyleSheet("background-color: #E6E6E6;")
-
- self.layout = QHBoxLayout()
- self.layout.setContentsMargins(0, 0, 0, 0)
- self.layout.setSpacing(0)
- self.setLayout(self.layout)
-
- def enterEvent(self, event: QtCore.QEvent):
- self.setStyleSheet("background-color: #D6D6D6;")
-
- def leaveEvent(self, event: QtCore.QEvent):
- self.setStyleSheet("background-color: #E6E6E6;")
-
- def mousePressEvent(self, event: QtGui.QMouseEvent):
- self.setStyleSheet("background-color: #C1C1C1;")
-
- def mouseReleaseEvent(self, event: QtGui.QMouseEvent):
- self.setStyleSheet("background-color: #D6D6D6;")
-
- def paintEvent(self, event: QPaintEvent):
- option = QStyleOption()
- option.initFrom(self)
- painter = QPainter(self)
- self.style().drawPrimitive(QStyle.PrimitiveElement(), option, painter, self)
- super().paintEvent(event)
-
- @staticmethod
- def icon(path: str, **kwargs):
- icon = BaseIconWidget(path, width=kwargs.get("width") or 28, height=kwargs.get("height") or 28)
- icon.setContentsMargins(kwargs.get("margin") or 5, 0, 0, 0)
- policy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
- policy.setHorizontalStretch(1)
- icon.setSizePolicy(policy)
- return icon
-
- @staticmethod
- def name(label: str, **kwargs):
- name = QLabel(label)
- name.setContentsMargins(kwargs.get("margin") or 10, 0, 0, 0)
- policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)
- policy.setHorizontalStretch(kwargs.get("stretch") or 4)
- name.setSizePolicy(policy)
- return name
-
- @staticmethod
- def editable_name(label: str, **kwargs):
- edit = QLineEdit()
- edit.setStyleSheet("QLineEdit { background: white; padding 0; }")
- policy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
- policy.setHorizontalStretch(kwargs.get("stretch") or 4)
- edit.setSizePolicy(policy)
- edit.setVisible(False)
- edit.setText(label)
- return edit
-
- @staticmethod
- def property(label, **kwargs):
- prop = QLabel(label)
- if kwargs.get("font_style"):
- prop.setStyleSheet(kwargs.get("font_style"))
- if kwargs.get("alignment"):
- prop.setAlignment(kwargs.get("alignment"))
-
- policy = QSizePolicy(
- kwargs.get("width_policy") or QSizePolicy.Ignored,
- kwargs.get("height_policy") or QSizePolicy.Preferred
- )
- policy.setHorizontalStretch(kwargs.get("stretch") or 2)
- prop.setSizePolicy(policy)
- return prop
-
- @staticmethod
- def separator(width=1):
- item = QLabel()
- item.setStyleSheet("QLabel { background-color: #CACACA }")
- item.setMaximumWidth(width)
- return item
-
-
-class BaseListWidget(QWidget):
- def __init__(self, parent=None):
- super().__init__(parent)
- self.widgets = []
- self.loading_widget = None
-
- self.layout = QVBoxLayout()
- self.layout.setSpacing(0)
- self.layout.addStretch()
- self.setLayout(self.layout)
-
- def load(self, widgets, empty_message="Empty", empty_full=True):
- self.clear()
-
- if not widgets:
- self.empty(empty_message, empty_full)
- else:
- for widget in widgets:
- self.widgets.append(widget)
- self.layout.insertWidget(self.layout.count() - 1, widget)
-
- def loading(self):
- self.clear()
- gif = QLabel(self)
- movie = QMovie(Resources.anim_loading)
- movie.setScaledSize(QSize(48, 48))
- gif.setAlignment(Qt.AlignCenter)
- gif.setMovie(movie)
-
- box = QGridLayout()
- box.addWidget(gif, 1, 0)
- box.setAlignment(Qt.AlignCenter)
-
- self.loading_widget = QWidget()
- self.loading_widget.setLayout(box)
- self.widgets.append(self.loading_widget)
- self.layout.addWidget(self.loading_widget, 1)
- movie.start()
-
- def clear(self):
- if self.loading_widget:
- self.layout.removeWidget(self.loading_widget)
- self.loading_widget.close()
- self.loading_widget = None
- for widget in self.widgets:
- self.layout.removeWidget(widget)
- widget.close()
- widget.deleteLater()
- self.widgets.clear()
-
- def empty(self, msg, full):
- if full:
- label = QLabel(msg)
- label.setAlignment(Qt.AlignCenter)
- label.setStyleSheet("color: #969696")
- box = QVBoxLayout()
- box.addWidget(label)
- box.addStretch()
-
- widget = QWidget()
- widget.setLayout(box)
- self.widgets.append(widget)
- self.layout.addWidget(widget)
- else:
- label = QLabel(msg)
- label.setStyleSheet("color: #969696")
- self.layout.insertWidget(self.layout.count() - 1, label)
diff --git a/src/gui/explorer/__init__.py b/src/gui/explorer/__init__.py
index 8449e1e..970dbd1 100644
--- a/src/gui/explorer/__init__.py
+++ b/src/gui/explorer/__init__.py
@@ -13,3 +13,40 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+
+from PyQt5.QtWidgets import QWidget, QVBoxLayout
+
+from core.main import Adb
+from core.managers import Global
+from gui.explorer.devices import DeviceExplorerWidget
+from gui.explorer.files import FileExplorerWidget
+
+
+class MainExplorer(QWidget):
+ def __init__(self, parent=None):
+ super(MainExplorer, self).__init__(parent)
+ self.body = QWidget(self)
+ self.setLayout(QVBoxLayout(self))
+
+ Global().communicate.files.connect(self.files)
+ Global().communicate.devices.connect(self.devices)
+
+ def files(self):
+ self.clear()
+
+ self.body = FileExplorerWidget(self)
+ self.layout().addWidget(self.body)
+ self.body.update()
+
+ def devices(self):
+ self.clear()
+ Adb.manager().clear_device()
+
+ self.body = DeviceExplorerWidget(self)
+ self.layout().addWidget(self.body)
+ self.body.update()
+
+ def clear(self):
+ self.layout().removeWidget(self.body)
+ self.body.close()
+ self.body.deleteLater()
diff --git a/src/gui/explorer/devices.py b/src/gui/explorer/devices.py
index d9ea61f..4b723c3 100644
--- a/src/gui/explorer/devices.py
+++ b/src/gui/explorer/devices.py
@@ -14,43 +14,154 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-from PyQt5.QtCore import Qt
+from typing import List, Any
+
+from PyQt5 import QtGui, QtCore
+from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex, QRect, QVariant, QSize
+from PyQt5.QtGui import QPalette, QPixmap, QMovie
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QStyledItemDelegate, QStyleOptionViewItem, QApplication, \
+ QStyle, QListView
from core.configurations import Resources
from core.main import Adb
from core.managers import Global
from data.models import Device, DeviceType, MessageData
from data.repositories import DeviceRepository
-from gui.abstract.base import BaseListWidget, BaseListItemWidget, BaseListHeaderWidget
-from helpers.tools import AsyncRepositoryWorker
+from helpers.tools import AsyncRepositoryWorker, read_string_from_file
+
+
+class DeviceItemDelegate(QStyledItemDelegate):
+ def sizeHint(self, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> QtCore.QSize:
+ result = super(DeviceItemDelegate, self).sizeHint(option, index)
+ result.setHeight(40)
+ return result
+
+ def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex):
+ if not index.data():
+ return super(DeviceItemDelegate, self).paint(painter, option, index)
+ top = option.rect.top()
+ bottom = option.rect.height()
+ first_start = option.rect.left() + 50
+ second_start = option.rect.left() + int(option.rect.width() / 2)
+ end = option.rect.width() + option.rect.left()
-class DeviceHeaderWidget(BaseListHeaderWidget):
- def __init__(self):
- super(DeviceHeaderWidget, self).__init__()
+ self.initStyleOption(option, index)
+ style = option.widget.style() if option.widget else QApplication.style()
+ style.drawControl(QStyle.CE_ItemViewItem, option, painter, option.widget)
+ painter.setPen(option.palette.color(QPalette.Normal, QPalette.Text))
- self.layout.addWidget(
- self.property('Connected devices', alignment=Qt.AlignCenter)
+ painter.drawText(
+ QRect(first_start, top, second_start - first_start - 4, bottom),
+ option.displayAlignment, index.data().name
)
+ painter.drawText(
+ QRect(second_start, top, end - second_start, bottom),
+ Qt.AlignCenter | option.displayAlignment, index.data().id
+ )
+
+
+class DeviceListModel(QAbstractListModel):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.items: List[Device] = []
+
+ def clear(self):
+ self.beginResetModel()
+ self.items.clear()
+ self.endResetModel()
-class DeviceListWidget(BaseListWidget):
+ def populate(self, devices: list):
+ self.beginResetModel()
+ self.items.clear()
+ self.items = devices
+ self.endResetModel()
+
+ def rowCount(self, parent: QModelIndex = ...) -> int:
+ return len(self.items)
+
+ def icon_path(self, index: QModelIndex = ...):
+ return Resources.icon_phone if self.items[index.row()].type == DeviceType.DEVICE \
+ else Resources.icon_phone_unknown
+
+ def data(self, index: QModelIndex, role: int = ...) -> Any:
+ if not index.isValid():
+ return QVariant()
+
+ if role == Qt.DisplayRole:
+ return self.items[index.row()]
+ elif role == Qt.DecorationRole:
+ return QPixmap(self.icon_path(index)).scaled(32, 32, Qt.KeepAspectRatio)
+ return QVariant()
+
+
+class DeviceExplorerWidget(QWidget):
DEVICES_WORKER_ID = 200
- def __init__(self, parent):
- super(DeviceListWidget, self).__init__(parent)
+ def __init__(self, parent=None):
+ super(DeviceExplorerWidget, self).__init__(parent)
+ self.setLayout(QVBoxLayout(self))
+
+ self.header = QLabel('Connected devices', self)
+ self.header.setAlignment(Qt.AlignCenter)
+ self.layout().addWidget(self.header)
+
+ self.list = QListView(self)
+ self.model = DeviceListModel(self.list)
+
+ self.list.setSpacing(1)
+ self.list.setModel(self.model)
+ self.list.clicked.connect(self.open)
+ self.list.setItemDelegate(DeviceItemDelegate(self.list))
+ self.list.setStyleSheet(read_string_from_file(Resources.style_device_list))
+ self.layout().addWidget(self.list)
+
+ self.loading = QLabel(self)
+ self.loading.setAlignment(Qt.AlignCenter)
+ self.loading_movie = QMovie(Resources.anim_loading, parent=self.loading)
+ self.loading_movie.setScaledSize(QSize(48, 48))
+ self.loading.setMovie(self.loading_movie)
+ self.layout().addWidget(self.loading)
+
+ self.empty_label = QLabel("No connected devices", self)
+ self.empty_label.setAlignment(Qt.AlignTop)
+ self.empty_label.setContentsMargins(15, 10, 0, 0)
+ self.empty_label.setStyleSheet("color: #969696; border: 1px solid #969696")
+ self.layout().addWidget(self.empty_label)
+
+ self.layout().setStretch(self.layout().count() - 1, 1)
+ self.layout().setStretch(self.layout().count() - 2, 1)
+
+ def update(self):
+ super(DeviceExplorerWidget, self).update()
worker = AsyncRepositoryWorker(
- worker_id=self.DEVICES_WORKER_ID,
name="Devices",
+ worker_id=self.DEVICES_WORKER_ID,
repository_method=DeviceRepository.devices,
arguments=(),
- response_callback=self.__async_response
+ response_callback=self._async_response
)
if Adb.worker().work(worker):
- self.loading()
+ # First Setup loading view
+ self.model.clear()
+ self.list.setHidden(True)
+ self.loading.setHidden(False)
+ self.empty_label.setHidden(True)
+ self.loading_movie.start()
+
+ # Then start async worker
worker.start()
- def __async_response(self, devices, error):
+ @property
+ def device(self):
+ if self.list and self.list.currentIndex() is not None:
+ return self.model.items[self.list.currentIndex().row()]
+
+ def _async_response(self, devices, error):
+ self.loading_movie.stop()
+ self.loading.setHidden(True)
+
if error:
Global().communicate.notification.emit(
MessageData(
@@ -59,30 +170,14 @@ def __async_response(self, devices, error):
body=f" {error} "
)
)
-
- widgets = []
- for device in devices:
- item = DeviceItemWidget(device)
- widgets.append(item)
- self.load(widgets, "No connected devices", False)
-
-
-class DeviceItemWidget(BaseListItemWidget):
- def __init__(self, device: Device):
- super(DeviceItemWidget, self).__init__()
- self.device = device
- if device.type == DeviceType.DEVICE:
- self.layout.addWidget(self.icon(Resources.icon_phone, width=32, height=32))
+ if not devices:
+ self.empty_label.setHidden(False)
else:
- self.layout.addWidget(self.icon(Resources.icon_phone_unknown, width=32, height=32))
-
- self.layout.addWidget(self.name(device.name))
- self.layout.addWidget(self.property(device.id))
-
- def mouseReleaseEvent(self, event):
- super(DeviceItemWidget, self).mouseReleaseEvent(event)
+ self.list.setHidden(False)
+ self.model.populate(devices)
- if event.button() == Qt.LeftButton and self.device.type == DeviceType.DEVICE:
+ def open(self):
+ if self.device.type == DeviceType.DEVICE:
if Adb.manager().set_device(self.device):
Global().communicate.files.emit()
else:
diff --git a/src/gui/explorer/files.py b/src/gui/explorer/files.py
index c80e13e..485d72a 100644
--- a/src/gui/explorer/files.py
+++ b/src/gui/explorer/files.py
@@ -15,148 +15,330 @@
# along with this program. If not, see .
import sys
+from typing import List, Any
-from PyQt5 import QtCore
-from PyQt5.QtCore import Qt, QPoint
-from PyQt5.QtGui import QPixmap
-from PyQt5.QtWidgets import QMenu, QAction, QMessageBox, QFileDialog
+from PyQt5 import QtCore, QtGui
+from PyQt5.QtCore import Qt, QPoint, QModelIndex, QAbstractListModel, QVariant, QRect, QSize, QEvent, QObject
+from PyQt5.QtGui import QPixmap, QColor, QPalette, QMovie, QKeySequence
+from PyQt5.QtWidgets import QMenu, QAction, QMessageBox, QFileDialog, QStyle, QWidget, QStyledItemDelegate, \
+ QStyleOptionViewItem, QApplication, QListView, QVBoxLayout, QLabel, QSizePolicy, QHBoxLayout
from core.configurations import Resources
from core.main import Adb
from core.managers import Global
from data.models import File, FileType, MessageData, MessageType
from data.repositories import FileRepository
-from gui.abstract.base import BaseListItemWidget, BaseListWidget, BaseListHeaderWidget
-from helpers.tools import AsyncRepositoryWorker, ProgressCallbackHelper
+from gui.explorer.toolbar import ParentButton, UploadTools, PathBar
+from helpers.tools import AsyncRepositoryWorker, ProgressCallbackHelper, read_string_from_file
+
+
+class FileHeaderWidget(QWidget):
+ def __init__(self, parent=None):
+ super(FileHeaderWidget, self).__init__(parent)
+ self.setLayout(QHBoxLayout(self))
+ policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)
+
+ self.file = QLabel('File', self)
+ self.file.setContentsMargins(45, 0, 0, 0)
+ policy.setHorizontalStretch(39)
+ self.file.setSizePolicy(policy)
+ self.layout().addWidget(self.file)
+
+ self.permissions = QLabel('Permissions', self)
+ self.permissions.setAlignment(Qt.AlignCenter)
+ policy.setHorizontalStretch(18)
+ self.permissions.setSizePolicy(policy)
+ self.layout().addWidget(self.permissions)
+
+ self.size = QLabel('Size', self)
+ self.size.setAlignment(Qt.AlignCenter)
+ policy.setHorizontalStretch(21)
+ self.size.setSizePolicy(policy)
+ self.layout().addWidget(self.size)
+
+ self.date = QLabel('Date', self)
+ self.date.setAlignment(Qt.AlignCenter)
+ policy.setHorizontalStretch(22)
+ self.date.setSizePolicy(policy)
+ self.layout().addWidget(self.date)
+
+ self.setStyleSheet("background: #E5E5E5; font-weight: 500;")
+
+
+class FileExplorerToolbar(QWidget):
+ def __init__(self, parent=None):
+ super(FileExplorerToolbar, self).__init__(parent)
+ self.setLayout(QHBoxLayout(self))
+
+ self.upload_tools = UploadTools(self)
+ self.upload_tools.setFixedHeight(32)
+ policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)
+ policy.setHorizontalStretch(1)
+ self.upload_tools.setSizePolicy(policy)
+ self.layout().addWidget(self.upload_tools)
+
+ self.parent_button = ParentButton(self)
+ self.parent_button.setFixedHeight(32)
+ policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)
+ policy.setHorizontalStretch(1)
+ self.parent_button.setSizePolicy(policy)
+ self.layout().addWidget(self.parent_button)
+
+ self.path_bar = PathBar(self)
+ policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)
+ policy.setHorizontalStretch(8)
+ self.path_bar.setSizePolicy(policy)
+ self.layout().addWidget(self.path_bar)
+
+
+class FileItemDelegate(QStyledItemDelegate):
+ def sizeHint(self, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex) -> QtCore.QSize:
+ result = super(FileItemDelegate, self).sizeHint(option, index)
+ result.setHeight(40)
+ return result
+
+ def setEditorData(self, editor: QWidget, index: QtCore.QModelIndex):
+ editor.setText(index.model().data(index, Qt.EditRole))
+
+ def updateEditorGeometry(self, editor: QWidget, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex):
+ editor.setGeometry(
+ option.rect.left() + 50, option.rect.top(), int(option.rect.width() / 2.5) - 54, option.rect.height()
+ )
+
+ def setModelData(self, editor: QWidget, model: QtCore.QAbstractItemModel, index: QtCore.QModelIndex):
+ model.setData(index, editor.text(), Qt.EditRole)
+
+ @staticmethod
+ def paint_line(painter: QtGui.QPainter, color: QColor, x, y, w, h):
+ painter.setPen(color)
+ painter.drawLine(x, y, w, h)
+
+ @staticmethod
+ def paint_text(painter: QtGui.QPainter, text: str, color: QColor, options, x, y, w, h):
+ painter.setPen(color)
+ painter.drawText(QRect(x, y, w, h), options, text)
+ def paint(self, painter: QtGui.QPainter, option: 'QStyleOptionViewItem', index: QtCore.QModelIndex):
+ if not index.data():
+ return super(FileItemDelegate, self).paint(painter, option, index)
-class FileHeaderWidget(BaseListHeaderWidget):
- def __init__(self):
- super(FileHeaderWidget, self).__init__()
+ self.initStyleOption(option, index)
+ style = option.widget.style() if option.widget else QApplication.style()
+ style.drawControl(QStyle.CE_ItemViewItem, option, painter, option.widget)
- self.layout.addWidget(
- BaseListItemWidget.name('File', margin=48)
+ line_color = QColor("#CCCCCC")
+ text_color = option.palette.color(QPalette.Normal, QPalette.Text)
+
+ top = option.rect.top()
+ bottom = option.rect.height()
+
+ first_start = option.rect.left() + 50
+ second_start = option.rect.left() + int(option.rect.width() / 2.5)
+ third_start = option.rect.left() + int(option.rect.width() / 1.75)
+ fourth_start = option.rect.left() + int(option.rect.width() / 1.25)
+ end = option.rect.width() + option.rect.left()
+
+ self.paint_text(
+ painter, index.data().name, text_color, option.displayAlignment,
+ first_start, top, second_start - first_start - 4, bottom
)
- self.layout.addWidget(
- self.property('Permissions', alignment=Qt.AlignCenter)
+ self.paint_line(painter, line_color, second_start - 2, top, second_start - 1, bottom)
+
+ self.paint_text(
+ painter, index.data().permissions, text_color, Qt.AlignCenter | option.displayAlignment,
+ second_start, top, third_start - second_start - 4, bottom
)
- self.layout.addWidget(
- self.property('Size', alignment=Qt.AlignCenter)
+ self.paint_line(painter, line_color, third_start - 2, top, third_start - 1, bottom)
+
+ self.paint_text(
+ painter, index.data().size, text_color, Qt.AlignCenter | option.displayAlignment,
+ third_start, top, fourth_start - third_start - 4, bottom
)
- self.layout.addWidget(
- self.property('Date', alignment=Qt.AlignCenter, stretch=3)
+ self.paint_line(painter, line_color, fourth_start - 2, top, fourth_start - 1, bottom)
+
+ self.paint_text(
+ painter, index.data().date, text_color, Qt.AlignCenter | option.displayAlignment,
+ fourth_start, top, end - fourth_start, bottom
)
-class FileListWidget(BaseListWidget):
- FILES_WORKER_ID = 300
+class FileListModel(QAbstractListModel):
+ def __init__(self, parent=None):
+ super().__init__(parent)
+ self.items: List[File] = []
- def __init__(self, parent):
- super(FileListWidget, self).__init__(parent)
+ def clear(self):
+ self.beginResetModel()
+ self.items.clear()
+ self.endResetModel()
- def update(self):
- super(FileListWidget, self).update()
- worker = AsyncRepositoryWorker(
- worker_id=self.FILES_WORKER_ID,
- name="Files",
- repository_method=FileRepository.files,
- response_callback=self.__async_response,
- arguments=()
- )
- if Adb.worker().work(worker):
- self.loading()
- worker.start()
+ def populate(self, files: list):
+ self.beginResetModel()
+ self.items.clear()
+ self.items = files
+ self.endResetModel()
- def __async_response(self, files, error):
- if error:
- print(error, file=sys.stderr)
- if error and not files:
- Global().communicate.notification.emit(
- MessageData(
- title='Files',
- timeout=15000,
- body=f" {error} "
+ def rowCount(self, parent: QModelIndex = ...) -> int:
+ return len(self.items)
+
+ def icon_path(self, index: QModelIndex = ...):
+ file_type = self.items[index.row()].type
+ if file_type == FileType.DIRECTORY:
+ return Resources.icon_folder
+ elif file_type == FileType.FILE:
+ return Resources.icon_file
+ elif file_type == FileType.LINK:
+ link_type = self.items[index.row()].link_type
+ if link_type == FileType.DIRECTORY:
+ return Resources.icon_link_folder
+ elif link_type == FileType.FILE:
+ return Resources.icon_link_file
+ return Resources.icon_link_file_unknown
+ return Resources.icon_file_unknown
+
+ def flags(self, index: QModelIndex) -> Qt.ItemFlags:
+ if not index.isValid():
+ return Qt.NoItemFlags
+
+ return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
+
+ def setData(self, index: QModelIndex, value: Any, role: int = ...) -> bool:
+ if role == Qt.EditRole and value:
+ data, error = FileRepository.rename(self.items[index.row()], value)
+ if error:
+ Global().communicate.notification.emit(
+ MessageData(
+ timeout=10000,
+ title="Rename",
+ body=f" {error} ",
+ )
)
- )
+ Global.communicate.files__refresh.emit()
+ return super(FileListModel, self).setData(index, value, role)
- widgets = []
- for file in files:
- item = FileItemWidget(self, file)
- widgets.append(item)
- self.load(widgets, "Folder is empty")
- Global().communicate.path_toolbar__refresh.emit()
+ def data(self, index: QModelIndex, role: int = ...) -> Any:
+ if not index.isValid():
+ return QVariant()
+ if role == Qt.DisplayRole:
+ return self.items[index.row()]
+ elif role == Qt.EditRole:
+ return self.items[index.row()].name
+ elif role == Qt.DecorationRole:
+ return QPixmap(self.icon_path(index)).scaled(32, 32, Qt.KeepAspectRatio)
+ return QVariant()
-class FileItemWidget(BaseListItemWidget):
+
+class FileExplorerWidget(QWidget):
+ FILES_WORKER_ID = 300
DOWNLOAD_WORKER_ID = 399
- def __init__(self, parent, file: File):
- super(FileItemWidget, self).__init__(parent)
- self.file = file
- self.name_widget = self.name(self.file.name)
- self.name_edit_widget = self.editable_name(self.file.name)
- self.name_edit_widget.installEventFilter(self)
+ def __init__(self, parent=None):
+ super(FileExplorerWidget, self).__init__(parent)
+ self.setLayout(QVBoxLayout(self))
+ self.layout().setSpacing(5)
- self.setContextMenuPolicy(Qt.CustomContextMenu)
- self.customContextMenuRequested.connect(self.context_menu)
+ self.toolbar = FileExplorerToolbar(self)
+ self.layout().addWidget(self.toolbar)
- self.layout.addWidget(
- self.icon(self.icon_path)
- )
+ self.header = FileHeaderWidget(self)
+ self.layout().addWidget(self.header)
- self.layout.addWidget(
- self.name_widget
- )
+ self.list = QListView(self)
+ self.model = FileListModel(self.list)
- self.layout.addWidget(
- self.name_edit_widget
- )
+ self.list.setSpacing(1)
+ self.list.setModel(self.model)
+ self.list.installEventFilter(self)
+ self.list.doubleClicked.connect(self.open)
+ self.list.setItemDelegate(FileItemDelegate(self.list))
+ self.list.setContextMenuPolicy(Qt.CustomContextMenu)
+ self.list.customContextMenuRequested.connect(self.context_menu)
+ self.list.setStyleSheet(read_string_from_file(Resources.style_file_list))
+ self.layout().addWidget(self.list)
- self.layout.addWidget(self.separator())
+ self.loading = QLabel(self)
+ self.loading.setAlignment(Qt.AlignCenter)
+ self.loading_movie = QMovie(Resources.anim_loading, parent=self.loading)
+ self.loading_movie.setScaledSize(QSize(48, 48))
+ self.loading.setMovie(self.loading_movie)
+ self.layout().addWidget(self.loading)
- self.layout.addWidget(
- self.property(self.file.permissions, font_style="italic", alignment=Qt.AlignCenter)
- )
+ self.empty_label = QLabel("Folder is empty", self)
+ self.empty_label.setAlignment(Qt.AlignCenter)
+ self.empty_label.setStyleSheet("color: #969696; border: 1px solid #969696")
+ self.layout().addWidget(self.empty_label)
- self.layout.addWidget(self.separator())
+ self.layout().setStretch(self.layout().count() - 1, 1)
+ self.layout().setStretch(self.layout().count() - 2, 1)
- self.layout.addWidget(
- self.property(self.file.size, alignment=Qt.AlignCenter)
- )
+ Global().communicate.files__refresh.connect(self.update)
- self.layout.addWidget(self.separator())
+ @property
+ def file(self):
+ if self.list and self.list.currentIndex():
+ return self.model.items[self.list.currentIndex().row()]
- self.layout.addWidget(
- self.property(self.file.date, alignment=Qt.AlignCenter, stretch=3)
+ def update(self):
+ super(FileExplorerWidget, self).update()
+ worker = AsyncRepositoryWorker(
+ name="Files",
+ worker_id=self.FILES_WORKER_ID,
+ repository_method=FileRepository.files,
+ response_callback=self._async_response,
+ arguments=()
)
+ if Adb.worker().work(worker):
+ # First Setup loading view
+ self.model.clear()
+ self.list.setHidden(True)
+ self.loading.setHidden(False)
+ self.empty_label.setHidden(True)
+ self.loading_movie.start()
+
+ # Then start async worker
+ worker.start()
+ Global().communicate.path_toolbar__refresh.emit()
- self.setToolTip(self.file.name)
- if self.file.type == FileType.LINK:
- self.setToolTip(self.file.link)
-
- @property
- def icon_path(self):
- if self.file.type == FileType.DIRECTORY:
- return Resources.icon_folder
- elif self.file.type == FileType.FILE:
- return Resources.icon_file
- elif self.file.type == FileType.LINK:
- if self.file.link_type == FileType.DIRECTORY:
- return Resources.icon_link_folder
- elif self.file.link_type == FileType.FILE:
- return Resources.icon_link_file
- return Resources.icon_link_file_unknown
- return Resources.icon_file_unknown
+ def close(self) -> bool:
+ Global().communicate.files__refresh.disconnect()
+ return super(FileExplorerWidget, self).close()
- def mouseReleaseEvent(self, event):
- super(FileItemWidget, self).mouseReleaseEvent(event)
+ def _async_response(self, files: list, error: str):
+ self.loading_movie.stop()
+ self.loading.setHidden(True)
- if event.button() == Qt.LeftButton:
- if Adb.manager().open(self.file):
- Global().communicate.files__refresh.emit()
+ if error:
+ print(error, file=sys.stderr)
+ if not files:
+ Global().communicate.notification.emit(
+ MessageData(
+ title='Files',
+ timeout=15000,
+ body=f" {error} "
+ )
+ )
+ if not files:
+ self.empty_label.setHidden(False)
+ else:
+ self.list.setHidden(False)
+ self.model.populate(files)
+ self.list.setFocus()
+
+ def eventFilter(self, obj: 'QObject', event: 'QEvent') -> bool:
+ if obj == self.list and \
+ event.type() == QEvent.KeyPress and \
+ event.matches(QKeySequence.InsertParagraphSeparator) and \
+ not self.list.isPersistentEditorOpen(self.list.currentIndex()):
+ self.open(self.list.currentIndex())
+ return super(FileExplorerWidget, self).eventFilter(obj, event)
+
+ def open(self, index: QModelIndex = ...):
+ if Adb.manager().open(self.model.items[index.row()]):
+ Global().communicate.files__refresh.emit()
def context_menu(self, pos: QPoint):
menu = QMenu()
@@ -171,7 +353,7 @@ def context_menu(self, pos: QPoint):
menu.addAction(action_move)
action_rename = QAction('Rename', self)
- action_rename.triggered.connect(self.open_rename)
+ action_rename.triggered.connect(self.rename)
menu.addAction(action_rename)
action_delete = QAction('Delete', self)
@@ -195,7 +377,7 @@ def context_menu(self, pos: QPoint):
menu.exec(self.mapToGlobal(pos))
@staticmethod
- def __async_response(data, error):
+ def default_response(data, error):
if error:
Global().communicate.notification.emit(
MessageData(
@@ -213,22 +395,8 @@ def __async_response(data, error):
)
)
- def open_rename(self):
- self.name_widget.setVisible(False)
- self.name_edit_widget.setVisible(True)
- self.name_edit_widget.setText(self.name_widget.text())
- self.name_edit_widget.returnPressed.connect(self.rename)
- self.name_edit_widget.setFocus()
-
- def close_rename(self):
- self.name_widget.setVisible(True)
- self.name_edit_widget.setVisible(False)
- self.name_edit_widget.disconnect()
-
- def eventFilter(self, obj: QtCore.QObject, event: QtCore.QEvent) -> bool:
- if event.type() == event.FocusOut and obj == self.name_edit_widget:
- self.close_rename()
- return super(FileItemWidget, self).eventFilter(obj, event)
+ def rename(self):
+ self.list.edit(self.list.currentIndex())
def delete(self):
reply = QMessageBox.critical(
@@ -258,26 +426,13 @@ def delete(self):
)
Global.communicate.files__refresh.emit()
- def rename(self):
- if self.name_edit_widget.text():
- data, error = FileRepository.rename(self.file, self.name_edit_widget.text())
- if error:
- Global().communicate.notification.emit(
- MessageData(
- timeout=10000,
- title="Rename",
- body=f" {error} ",
- )
- )
- Global.communicate.files__refresh.emit()
-
def download(self):
helper = ProgressCallbackHelper()
worker = AsyncRepositoryWorker(
worker_id=self.DOWNLOAD_WORKER_ID,
name="Download",
repository_method=FileRepository.download,
- response_callback=FileItemWidget.__async_response,
+ response_callback=self.default_response,
arguments=(helper.progress_callback.emit, self.file.path)
)
if Adb.worker().work(worker):
@@ -299,8 +454,10 @@ def download_to(self):
worker_id=self.DOWNLOAD_WORKER_ID,
name="Download",
repository_method=FileRepository.download_to,
- response_callback=FileItemWidget.__async_response,
- arguments=(helper.progress_callback.emit, self.file.path, dir_name)
+ response_callback=self.default_response,
+ arguments=(
+ helper.progress_callback.emit, self.file.path, dir_name
+ )
)
if Adb.worker().work(worker):
Global().communicate.notification.emit(
@@ -315,8 +472,8 @@ def download_to(self):
def file_properties(self):
file, error = FileRepository.file(self.file.path)
- if file:
- self.file = file
+ file = file if file else self.file
+
if error:
Global().communicate.notification.emit(
MessageData(
@@ -326,20 +483,23 @@ def file_properties(self):
)
)
- info = f"
{str(self.file)}
"
- info += f"
Name: {self.file.name or '-'}
"
- info += f"Owner: {self.file.owner or '-'}
"
- info += f"Group: {self.file.group or '-'}
"
- info += f"Size: {self.file.size or '-'}
"
- info += f"Permissions: {self.file.permissions or '-'}
"
- info += f"Date: {self.file.date__raw or '-'}
"
- info += f"Type: {self.file.type or '-'}
"
+ info = f"
{str(file)}
"
+ info += f"Name: {file.name or '-'}
"
+ info += f"Owner: {file.owner or '-'}
"
+ info += f"Group: {file.group or '-'}
"
+ info += f"Size: {file.size or '-'}
"
+ info += f"Permissions: {file.permissions or '-'}
"
+ info += f"Date: {file.date__raw or '-'}
"
+ info += f"Type: {file.type or '-'}
"
- if self.file.type == FileType.LINK:
- info += f"Links to: {self.file.link or '-'}
"
+ if file.type == FileType.LINK:
+ info += f"Links to: {file.link or '-'}
"
properties = QMessageBox(self)
- properties.setIconPixmap(QPixmap(self.icon_path).scaled(128, 128, Qt.KeepAspectRatio))
+ properties.setStyleSheet("background-color: #DDDDDD")
+ properties.setIconPixmap(
+ QPixmap(self.model.icon_path(self.list.currentIndex())).scaled(128, 128, Qt.KeepAspectRatio)
+ )
properties.setWindowTitle('Properties')
properties.setInformativeText(info)
properties.exec_()
diff --git a/src/gui/explorer/main.py b/src/gui/explorer/main.py
deleted file mode 100644
index 50c47c7..0000000
--- a/src/gui/explorer/main.py
+++ /dev/null
@@ -1,121 +0,0 @@
-# ADB File Explorer `tool`
-# Copyright (C) 2022 Azat Aldeshov azata1919@gmail.com
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-
-from PyQt5.QtWidgets import QWidget, QScrollArea, QVBoxLayout, QHBoxLayout, QSizePolicy
-
-from core.main import Adb
-from core.managers import Global
-from gui.explorer.devices import DeviceHeaderWidget, DeviceListWidget
-from gui.explorer.files import FileHeaderWidget, FileListWidget
-from gui.explorer.toolbar import UploadTools, ParentButton, PathBar
-
-
-class FileExplorerToolbar(QWidget):
- def __init__(self, parent):
- super(FileExplorerToolbar, self).__init__(parent)
- self.explorer = parent
- self.layout = QHBoxLayout()
- self.setLayout(self.layout)
-
- self.upload = UploadTools(self)
- self.upload.setFixedHeight(32)
- policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
- policy.setHorizontalStretch(1)
- self.upload.setSizePolicy(policy)
- self.layout.addWidget(self.upload)
-
- self.parent_dir = ParentButton(self)
- self.parent_dir.setFixedHeight(32)
- policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
- policy.setHorizontalStretch(1)
- self.parent_dir.setSizePolicy(policy)
- self.layout.addWidget(self.parent_dir)
-
- self.path_bar = PathBar(self)
- policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Fixed)
- policy.setHorizontalStretch(8)
- self.path_bar.setSizePolicy(policy)
- self.layout.addWidget(self.path_bar)
-
-
-class Explorer(QWidget):
- def __init__(self, main_window):
- super().__init__()
- self.main_window = main_window
- self.layout = QVBoxLayout()
- self.setLayout(self.layout)
-
- self.body = QWidget()
- self.header = QWidget()
- self.toolbar = QWidget()
- self.scroll = QScrollArea(self)
- self.scroll.setWidgetResizable(True)
-
- Global().communicate.files.connect(self.files)
- Global().communicate.devices.connect(self.devices)
-
- def __update_files(self):
- self.scroll.widget().update()
- Global().communicate.path_toolbar__refresh.emit()
-
- def files(self):
- self.clear()
- self.toolbar = FileExplorerToolbar(self)
- self.layout.addWidget(self.toolbar)
-
- self.header = FileHeaderWidget()
- self.layout.addWidget(self.header)
-
- self.body = FileListWidget(self)
- self.scroll.setWidget(self.body)
- self.layout.addWidget(self.scroll)
-
- self.scroll.widget().update()
-
- Global().communicate.files__refresh.connect(print)
- Global().communicate.files__refresh.disconnect()
- Global().communicate.files__refresh.connect(self.__update_files)
-
- def devices(self):
- self.clear()
- Adb.manager().clear_device()
- self.toolbar = QWidget()
-
- self.header = DeviceHeaderWidget()
- self.layout.addWidget(self.header)
-
- self.body = DeviceListWidget(self)
- self.scroll.setWidget(self.body)
- self.layout.addWidget(self.scroll)
-
- def clear(self):
- self.toolbar.close()
- self.toolbar.deleteLater()
- self.layout.removeWidget(self.toolbar)
- del self.toolbar
-
- self.header.close()
- self.header.deleteLater()
- self.layout.removeWidget(self.header)
- del self.header
-
- self.body.close()
- self.body.deleteLater()
- self.layout.removeWidget(self.body)
- del self.body
-
- self.layout.removeWidget(self.scroll)
- self.scroll.setWidget(None)
diff --git a/src/gui/explorer/toolbar.py b/src/gui/explorer/toolbar.py
index 0def9d8..54db106 100644
--- a/src/gui/explorer/toolbar.py
+++ b/src/gui/explorer/toolbar.py
@@ -22,7 +22,6 @@
from core.managers import Global
from data.models import MessageData, MessageType
from data.repositories import FileRepository
-from gui.explorer.files import FileListWidget
from helpers.tools import AsyncRepositoryWorker, ProgressCallbackHelper
@@ -145,7 +144,7 @@ def __init__(self, parent):
@staticmethod
def __action__():
- if Adb.worker().check(FileListWidget.FILES_WORKER_ID) and Adb.manager().up():
+ if Adb.worker().check(300) and Adb.manager().up():
Global().communicate.files__refresh.emit()
diff --git a/src/gui/others/help.py b/src/gui/help/__init__.py
similarity index 91%
rename from src/gui/others/help.py
rename to src/gui/help/__init__.py
index d82d7ab..a9827f0 100644
--- a/src/gui/others/help.py
+++ b/src/gui/help/__init__.py
@@ -15,17 +15,17 @@
# along with this program. If not, see .
from PyQt5.QtCore import Qt
-from PyQt5.QtGui import QIcon
+from PyQt5.QtGui import QPixmap, QIcon
from PyQt5.QtWidgets import QWidget, QLabel, QApplication
-from gui.abstract.base import BaseIconWidget
from core.configurations import Resources, Application
class About(QWidget):
def __init__(self):
super(QWidget, self).__init__()
- icon = BaseIconWidget(Resources.icon_logo, width=64, height=64, context=self)
+ icon = QLabel(self)
+ icon.setPixmap(QPixmap(Resources.icon_logo).scaled(64, 64, Qt.KeepAspectRatio))
icon.move(168, 40)
about_text = "
"
about_text += "ADB File Explorer
"
@@ -47,4 +47,4 @@ def __init__(self):
self.setFixedWidth(400)
center = QApplication.desktop().availableGeometry(self).center()
- self.move(int(center.x() - self.width() * 0.5), int(center.y() - self.height() * 0.5))
+ self.move(int(center.x() - self.width() * 0.5), int(center.y() - self.height() * 0.5))
\ No newline at end of file
diff --git a/src/gui/others/additional.py b/src/gui/others/additional.py
index 7d7a7af..4f5bdc9 100644
--- a/src/gui/others/additional.py
+++ b/src/gui/others/additional.py
@@ -41,8 +41,7 @@ def __init__(self, parent, text):
self.text.setAlignment(Qt.AlignCenter)
self.layout.addWidget(self.text)
- self.setMinimumWidth(192)
- self.setMinimumHeight(192)
+ self.setMinimumSize(192, 192)
self.setWindowModality(Qt.WindowModal)
self.setWindowFlags(QtCore.Qt.Dialog | Qt.Window | Qt.CustomizeWindowHint)
diff --git a/src/gui/others/notification.py b/src/gui/others/notification.py
index c88fe29..ad572f2 100644
--- a/src/gui/others/notification.py
+++ b/src/gui/others/notification.py
@@ -24,6 +24,7 @@
from core.configurations import Resources
from data.models import MessageType
+from helpers.tools import read_string_from_file
class BaseMessage(QWidget):
@@ -103,7 +104,7 @@ def create_close(self):
button.setIcon(QIcon(Resources.icon_close))
button.setFixedSize(32, 32)
button.setIconSize(QSize(10, 10))
- button.setStyleSheet(Resources.read_string_from_file(Resources.style_notification_button))
+ button.setStyleSheet(read_string_from_file(Resources.style_notification_button))
button.clicked.connect(lambda: self.close() or None)
self.header.addWidget(button)
diff --git a/src/gui/window.py b/src/gui/window.py
index af347ea..dc64f02 100644
--- a/src/gui/window.py
+++ b/src/gui/window.py
@@ -22,8 +22,8 @@
from core.managers import Global
from data.models import MessageData, MessageType
from data.repositories import DeviceRepository
-from gui.explorer.main import Explorer
-from gui.others.help import About
+from gui.explorer import MainExplorer
+from gui.help import About
from gui.others.notification import NotificationCenter
from helpers.tools import AsyncRepositoryWorker
@@ -154,14 +154,12 @@ def __init__(self):
super(MainWindow, self).__init__()
self.setMenuBar(MenuBar(self))
- self.setCentralWidget(Explorer(self))
+ self.setCentralWidget(MainExplorer(self))
- self.move(300, 300)
self.resize(640, 480)
- self.setMinimumWidth(480)
- self.setMinimumHeight(360)
- self.setWindowIcon(QIcon(Resources.icon_logo))
+ self.setMinimumSize(480, 360)
self.setWindowTitle('ADB File Explorer')
+ self.setWindowIcon(QIcon(Resources.icon_logo))
# Show Devices Widget
Global().communicate.devices.emit()
diff --git a/src/helpers/tools.py b/src/helpers/tools.py
index c0deb74..4205cc6 100644
--- a/src/helpers/tools.py
+++ b/src/helpers/tools.py
@@ -19,7 +19,7 @@
import subprocess
from PyQt5 import QtCore
-from PyQt5.QtCore import QThread, QObject
+from PyQt5.QtCore import QThread, QObject, QFile, QIODevice, QTextStream
from PyQt5.QtWidgets import QWidget
from adb_shell.auth.keygen import keygen
from adb_shell.auth.sign_pythonrsa import PythonRSASigner
@@ -131,3 +131,12 @@ def get_python_rsa_keys_signer(rerun=True) -> PythonRSASigner:
os.mkdir(path)
keygen(key)
return get_python_rsa_keys_signer(False)
+
+
+def read_string_from_file(path: str):
+ file = QFile(path)
+ if file.open(QIODevice.ReadOnly | QIODevice.Text):
+ text = QTextStream(file).readAll()
+ file.close()
+ return text
+ return str()