Giter Site home page Giter Site logo

adbfileexplorer's Introduction

Hi there ๐Ÿ‘‹

I'm Azat

  • ๐Ÿ”ญ Iโ€™m currently working on d66b76b4e1433e63c7d0dbc2d188fea900df98cb

adbfileexplorer's People

Contributors

aldeshov avatar ctrlcctrlv avatar dandv avatar keenox avatar tomiwa-ot avatar werve avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

adbfileexplorer's Issues

Module not found

I got the following error:

from PyQt5.QtWidgets import QApplication
ImportError: No module named PyQt5.QtWidgets

Progress bar for pull and push

Hi!

I love ADBFileExplorer! There is no progress bar when pushing to or pulling from the device, however. Also, I've noticed that you are using a custom wrapper around adb instead of a library like python-adb, which has this functionality implemented: you can get transfer progress when pushing and pulling.

So, you could use python-adb to add a progress bar.
I hope it will help you!

feedback and improve tips

for ages i searched for an application to also rename and delete files on phone using remote pc. thank you!
still some very important features are missing which hurt the use of application like sorting on files, better gui, different views like thumbnails or lists and viewing folders which have special characters like underline( _ ). i have such a folder and have plenty of content in it but applicatons said that the folder is empty.

WSA support

Adding support for "Windows subsystem for android" in ADBFileExplorer.

We all know that transferring files to Windows subsystem for android is a hassle.
There is already a script which pushes files to WSA using adb: EasySideload-WSA
It works but it isn't as near as ADBFileExplorer, you can't browse WSA files or even pull them and it doesn't have a GUI, I think it may be useful to get an idea for how to add WSA support in ADBFileExplorer.
So adding support for WSA in ADBFileExplorer would be very useful.
Thanks.

modified main.py file to enable select feature

`# ADB File Explorer

Copyright (C) 2

file_selection_action = QAction('Select Multiple Files', self)
file_selection_action.triggered.connect(self.select_multiple_files)
self.file_menu.addAction(file_selection_action)
022 Azat Aldeshov
import sys
from typing import Any

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, QTextEdit,
QMainWindow

from app.core.configurations import Resources
from app.core.main import Adb
from app.core.managers import Global
from app.data.models import FileType, MessageData, MessageType
from app.data.repositories import FileRepository
from app.gui.explorer.toolbar import ParentButton, UploadTools, PathBar
from app.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("QWidget { background-color: #E5E5E5; font-weight: 500; border: 1px solid #C0C0C0 }")

class FileExplorerToolbar(QWidget):
def init(self, parent=None):
super(FileExplorerToolbar, self).init(parent)
self.setLayout(QHBoxLayout(self))
policy = QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Preferred)
policy.setHorizontalStretch(1)

    self.upload_tools = UploadTools(self)
    self.upload_tools.setSizePolicy(policy)
    self.layout().addWidget(self.upload_tools)

    self.parent_button = ParentButton(self)
    self.parent_button.setSizePolicy(policy)
    self.layout().addWidget(self.parent_button)

    self.path_bar = PathBar(self)
    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() + 48, option.rect.top(), int(option.rect.width() / 2.5) - 55, 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)

    self.initStyleOption(option, index)
    style = option.widget.style() if option.widget else QApplication.style()
    style.drawControl(QStyle.CE_ItemViewItem, option, painter, option.widget)

    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.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.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.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 FileListModel(QAbstractListModel):
def init(self, parent=None):
super().init(parent)
self.items = []

def clear(self):
    self.beginResetModel()
    self.items.clear()
    self.endResetModel()

def populate(self, files: list):
    self.beginResetModel()
    self.items.clear()
    self.items = files
    self.endResetModel()

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="<span style='color: red; font-weight: 600'> %s </span>" % error,
                )
            )
        Global.communicate.files__refresh.emit()
    return super(FileListModel, self).setData(index, value, role)

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 FileExplorerWidget(QWidget):
FILES_WORKER_ID = 300
DOWNLOAD_WORKER_ID = 399

def __init__(self, parent=None):
    super(FileExplorerWidget, self).__init__(parent)
    self.main_layout = QVBoxLayout(self)

    self.toolbar = FileExplorerToolbar(self)
    self.main_layout.addWidget(self.toolbar)

    self.header = FileHeaderWidget(self)
    self.main_layout.addWidget(self.header)

    self.list = QListView(self)
    self.model = FileListModel(self.list)

    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.list.setSelectionMode(QListView.SelectionMode.ExtendedSelection)
    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.main_layout.addWidget(self.loading)

    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.main_layout.setStretch(self.layout().count() - 1, 1)
    self.main_layout.setStretch(self.layout().count() - 2, 1)

    self.text_view_window = None
    self.setLayout(self.main_layout)

    Global().communicate.files__refresh.connect(self.update)

@property
def file(self):
    if self.list and self.list.currentIndex():
        return self.model.items[self.list.currentIndex().row()]

@property
def files(self):
    if self.list and len(self.list.selectedIndexes()) > 0:
        return map(lambda index: self.model.items[index.row()], self.list.selectedIndexes())

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()

def close(self) -> bool:
    Global().communicate.files__refresh.disconnect()
    return super(FileExplorerWidget, self).close()

def _async_response(self, files: list, error: str):
    self.loading_movie.stop()
    self.loading.setHidden(True)

    if error:
        print(error, file=sys.stderr)
        if not files:
            Global().communicate.notification.emit(
                MessageData(
                    title='Files',
                    timeout=15000,
                    body="<span style='color: red; font-weight: 600'> %s </span>" % 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()
    menu.addSection("Actions")

    action_copy = QAction('Copy to...', self)
    action_copy.setDisabled(True)
    menu.addAction(action_copy)

    action_move = QAction('Move to...', self)
    action_move.setDisabled(True)
    menu.addAction(action_move)

    action_rename = QAction('Rename', self)
    action_rename.triggered.connect(self.rename)
    menu.addAction(action_rename)

    action_open_file = QAction('Open', self)
    action_open_file.triggered.connect(self.open_file)
    menu.addAction(action_open_file)

    action_delete = QAction('Delete', self)
    action_delete.triggered.connect(self.delete)
    menu.addAction(action_delete)

    action_download = QAction('Download', self)
    action_download.triggered.connect(self.download_files)
    menu.addAction(action_download)

    action_download_to = QAction('Download to...', self)
    action_download_to.triggered.connect(self.download_to)
    menu.addAction(action_download_to)

    menu.addSeparator()

    action_properties = QAction('Properties', self)
    action_properties.triggered.connect(self.file_properties)
    menu.addAction(action_properties)

    menu.exec(self.mapToGlobal(pos))

@staticmethod
def default_response(data, error):
    if error:
        Global().communicate.notification.emit(
            MessageData(
                title='Download error',
                timeout=15000,
                body="<span style='color: red; font-weight: 600'> %s </span>" % error
            )
        )
    if data:
        Global().communicate.notification.emit(
            MessageData(
                title='Downloaded',
                timeout=15000,
                body=data
            )
        )

def rename(self):
    self.list.edit(self.list.currentIndex())

def open_file(self):
    # QDesktopServices.openUrl(QUrl.fromLocalFile("downloaded_path")) open via external app
    if not self.file.isdir:
        data, error = FileRepository.open_file(self.file)
        if error:
            Global().communicate.notification.emit(
                MessageData(
                    title='File',
                    timeout=15000,
                    body="<span style='color: red; font-weight: 600'> %s </span>" % error
                )
            )
        else:
            self.text_view_window = TextView(self.file.name, data)
            self.text_view_window.show()

def delete(self):
    file_names = ', '.join(map(lambda f: f.name, self.files))
    reply = QMessageBox.critical(
        self,
        'Delete',
        "Do you want to delete '%s'? It cannot be undone!" % file_names,
        QMessageBox.Yes | QMessageBox.No, QMessageBox.No
    )

    if reply == QMessageBox.Yes:
        for file in self.files:
            data, error = FileRepository.delete(file)
            if data:
                Global().communicate.notification.emit(
                    MessageData(
                        timeout=10000,
                        title="Delete",
                        body=data,
                    )
                )
            if error:
                Global().communicate.notification.emit(
                    MessageData(
                        timeout=10000,
                        title="Delete",
                        body="<span style='color: red; font-weight: 600'> %s </span>" % error,
                    )
                )
        Global.communicate.files__refresh.emit()

def download_to(self):
    dir_name = QFileDialog.getExistingDirectory(self, 'Download to', '~')
    if dir_name:
        self.download_files(dir_name)

def download_files(self, destination: str = None):
    for file in self.files:
        helper = ProgressCallbackHelper()
        worker = AsyncRepositoryWorker(
            worker_id=self.DOWNLOAD_WORKER_ID,
            name="Download",
            repository_method=FileRepository.download,
            response_callback=self.default_response,
            arguments=(
                helper.progress_callback.emit, file.path, destination
            )
        )
        if Adb.worker().work(worker):
            Global().communicate.notification.emit(
                MessageData(
                    title="Downloading to",
                    message_type=MessageType.LOADING_MESSAGE,
                    message_catcher=worker.set_loading_widget
                )
            )
            helper.setup(worker, worker.update_loading_widget)
            worker.start()

def file_properties(self):
    file, error = FileRepository.file(self.file.path)
    file = file if file else self.file

    if error:
        Global().communicate.notification.emit(
            MessageData(
                timeout=10000,
                title="Opening folder",
                body="<span style='color: red; font-weight: 600'> %s </span>" % error,
            )
        )

    info = "<br/><u><b>%s</b></u><br/>" % str(file)
    info += "<pre>Name:        %s</pre>" % file.name or '-'
    info += "<pre>Owner:       %s</pre>" % file.owner or '-'
    info += "<pre>Group:       %s</pre>" % file.group or '-'
    info += "<pre>Size:        %s</pre>" % file.raw_size or '-'
    info += "<pre>Permissions: %s</pre>" % file.permissions or '-'
    info += "<pre>Date:        %s</pre>" % file.raw_date or '-'
    info += "<pre>Type:        %s</pre>" % file.type or '-'

    if file.type == FileType.LINK:
        info += "<pre>Links to:    %s</pre>" % file.link or '-'

    properties = QMessageBox(self)
    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_()

class TextView(QMainWindow):
def init(self, filename, data):
QMainWindow.init(self)

    self.setMinimumSize(QSize(500, 300))
    self.setWindowTitle(filename)

    self.text_edit = QTextEdit(self)
    self.setCentralWidget(self.text_edit)
    self.text_edit.insertPlainText(data)
    self.text_edit.move(10, 10)

def select_multiple_files(self):
file_names, _ = QFileDialog.getOpenFileNames(self, 'Select Files')
if file_names:
self.handle_selected_files(file_names)

def handle_selected_files(self, file_names: list):
# Implement your logic here
# For now, let's just print the selected files
print("Selected files:", file_names)
`
modified_files.zip

App has no root access

When accessing some root folders with the file manger (e.g. /efs) there are no files shown inside...!? it seems the app has adb without root - only adb (root) shell works...!?

Didn't work for me.

Downloaded and installed Windows version, double-clicked on the .exe
It shows my phone as connected, but with a red icon overlaying it and I cannot explore.

Better readme

Hi, I just installed your tool and I think the readme should be improved.

  • You state "adb (binary) should exist in project root folder". It's unclear from the doc what this is, since when getting the source zip, the root folder is the one with the readme.md file. Having adb there does not work, it needs to be in the src folder.
  • You state one should use adb binary. You do not write, that I have to uncomment adb.set_core(Adb.EXTERNAL_TOOL_ADB) to do that. Also I was under the impression I would not have to install adb-shell when using adb binary, yet I have to do that. Please write in the readme, that you have to uncomment that line, or build something that autodetects adb binary or let one choose from within the program.

Thank you

Preserve timestamp

I would like to suggest that it would be better to transfer to PC (pull) with the option adb pull -a which preserves file timestamps.

existing Files

Hello,

thanks for ADB File Explorer - so much faster than the bloddy MTP...
One question: What does ADB_FE do if I "download to..." a folder and the Folder already exists with some files already in it (e.g. from a previous transfer). Will it overwrite the existing files or skip them?

Regards,
Hendrik

Can't delete or rename files or folders with parentheses in their names

Whenever I try deleting or renaming a file or folder with parentheses in its name while it's on my phone, the operation fails with the error "/system/bin/sh: syntax error: unexpected '('". According to a couple of posts I found on Stack Exchange, this is apparently because dash is being used instead of bash. Idk how to fix this, assuming this is truly an issue on my end.

I'm running this on Windows 10 x64, and "python -VV" reports "Python 3.8.5 (tags/v3.8.5:580fbb0, Jul 20 2020, 15:57:54) [MSC v.1924 64 bit (AMD64)]"

My src/app/settings.json is as follows:

{
  "adb_path": "adb",
  "adb_core": "external",
  "adb_kill_server_at_exit": false,
  "preserve_timestamp": true,
  "adb_run_as_root": false
}

I've tried running it with "adb_core": "external", commented out or removed, but it gave me the following error in the console window:

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
ADB File Explorer v1.3.0
Copyright (C) 2022 Azat Aldeshov
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Platform Windows-10-10.0.19041-SP0
adb server stopped.
Using Python "adb-shell" version 0.4.3
ERROR:root:Unexpected error=LIBUSB_ERROR_NOT_SUPPORTED [-12], type(error)=<class 'usb1.USBErrorNotSupported'>
Traceback (most recent call last):
  File "C:\Other Programs\ADB File Explorer\src\app\data\repositories\python_adb.py", line 226, in devices
    device_id = device.getSerialNumber()
  File "C:\Other Programs\ADB File Explorer\venv\lib\site-packages\usb1\__init__.py", line 2019, in getSerialNumber
    return self.open().getSerialNumber()
  File "C:\Other Programs\ADB File Explorer\venv\lib\site-packages\usb1\__init__.py", line 2055, in open
    mayRaiseUSBError(libusb1.libusb_open(self.device_p, byref(handle)))
  File "C:\Other Programs\ADB File Explorer\venv\lib\site-packages\usb1\__init__.py", line 127, in mayRaiseUSBError
    __raiseUSBError(value)
  File "C:\Other Programs\ADB File Explorer\venv\lib\site-packages\usb1\__init__.py", line 119, in raiseUSBError
    raise __STATUS_TO_EXCEPTION_DICT.get(value, __USBError)(value)
usb1.USBErrorNotSupported: LIBUSB_ERROR_NOT_SUPPORTED [-12]

Crash on too many open files

When attempting to download a lot of files (e.g. from Camera), the app crashes with:

(process:64670): GLib-ERROR **: 01:46:40.739: Creating pipes for GWakeup: Too many open files
./run.sh: line 8: 64670 Trace/breakpoint trap (core dumped) python ./src/app

I was using adb-shell because external adb was unable to read the device at all:

image

There were no other adb processes running and the app had started fine (except for lacking venv):

$ ./run.sh
./run.sh: line 1: ./venv/bin/activate: No such file or directory
Android Debug Bridge version 1.0.41
Version 28.0.2-debian
Installed as /usr/lib/android-sdk/platform-tools/adb

* daemon not running; starting now at tcp:5037
* daemon started successfully

ADB server running...

Dark theme support

The program seems to have hard coded colors, which works well as long as you have a light theme configured for Qt apps, but breaks once you use a dark theme. I attached a screenshot of the program using the "Breeze dark" theme on KDE Plasma:

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.