Skip to content

Commit

Permalink
fix: app hangs when access mtp device
Browse files Browse the repository at this point in the history
As title.

Log: fix a access issue.
Bug: https://pms.uniontech.com/bug-view-289223.html
  • Loading branch information
rb-union committed Feb 24, 2025
1 parent f062928 commit 4a0d5c0
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 137 deletions.
1 change: 1 addition & 0 deletions src/qml/Control/ListView/ThumbnailListViewAlbum.qml
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ FocusScope {
keyNavigationWraps: false
boundsBehavior: Flickable.StopAtBounds
flickDeceleration: 10000
model: main.model

//激活滚动条
ScrollBar.vertical: ScrollBar {
Expand Down
20 changes: 15 additions & 5 deletions src/qml/ThumbnailImageView/DeviceAlbum/DeviceAlbum.qml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ BaseView {
property string deviceName: GStatus.currentDeviceName
property int filterType: 0
property int currentImportIndex: 0
property var numLabelText: getNumLabelText(filterType)
property var numLabelText
property string selectedText: getSelectedText(selectedPaths)
property alias selectedPaths: theView.selectedPaths

Expand Down Expand Up @@ -50,12 +50,16 @@ BaseView {
getNumLabelText()
}

// 刷新总数标签
function getNumLabelText() {
// request load data
albumControl.getDeviceAlbumInfoCountAsync(devicePath)
}

// 刷新总数标签
function setNumLabelText(photoCount, videoCount) {
//QML的翻译不支持%n的特性,只能拆成这种代码

var photoCountText = ""
var photoCount = albumControl.getDeviceAlbumInfoConut(devicePath, 3)
if(photoCount === 0) {
photoCountText = ""
} else if(photoCount === 1) {
Expand All @@ -65,7 +69,6 @@ BaseView {
}

var videoCountText = ""
var videoCount = albumControl.getDeviceAlbumInfoConut(devicePath, 4)
if(videoCount === 0) {
videoCountText = ""
} else if(videoCount === 1) {
Expand All @@ -74,7 +77,7 @@ BaseView {
videoCountText = qsTr("%1 videos").arg(videoCount)
}

var numLabelText = filterType == 0 ? (photoCountText + (videoCountText !== "" ? ((photoCountText !== "" ? " " : "") + videoCountText) : ""))
numLabelText = filterType == 0 ? (photoCountText + (videoCountText !== "" ? ((photoCountText !== "" ? " " : "") + videoCountText) : ""))
: (filterType == 1 ? photoCountText : videoCountText)
if (visible) {
GStatus.statusBarNumText = numLabelText
Expand Down Expand Up @@ -112,6 +115,13 @@ BaseView {
GStatus.selectedPaths = selectedPaths
}
}

// device info load finished
function onDeviceAlbumInfoCountChanged(loadDevicePath, picCount, videoCount) {
if (loadDevicePath === devicePath) {
setNumLabelText(picCount, videoCount)
}
}
}

// 设备相册标题栏区域
Expand Down
195 changes: 83 additions & 112 deletions src/src/albumControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,41 +785,6 @@ void AlbumControl::slotMonitorDestroyed(int UID)
emit sigDeleteCustomAlbum(UID);
}

void AlbumControl::sltLoadMountFileList(const QString &path)
{
QElapsedTimer time;
time.start();
QString strPath = path;
if (!m_PhonePicFileMap.contains(strPath)) {
//获取所选文件类型过滤器
QStringList filters;
for (QString i : LibUnionImage_NameSpace::unionImageSupportFormat()) {
filters << "*." + i;
}

for (QString i : LibUnionImage_NameSpace::videoFiletypes()) {
filters << "*." + i;
}
//定义迭代器并设置过滤器,包括子目录:QDirIterator::Subdirectories
QDirIterator dir_iterator(strPath,
filters,
QDir::Files/* | QDir::NoSymLinks*/,
QDirIterator::Subdirectories);
QStringList allfiles;
while (dir_iterator.hasNext()) {
dir_iterator.next();
allfiles << dir_iterator.filePath();
}
//重置标志位,可以执行线程
m_PhonePicFileMap[strPath] = allfiles;
//发送信号
} else {
//已加载过的设备,直接发送缓存的路径
}

qDebug() << __FUNCTION__ << QString(" load device path:%1 cost [%2]ms").arg(path).arg(time.elapsed());
}

void AlbumControl::onDeviceRemoved(const QString &deviceKey, DeviceType type)
{
qDebug() << QString("deviceKey:%1 DeviceType:%2").arg(deviceKey).arg(static_cast<int>(type));
Expand Down Expand Up @@ -2263,102 +2228,108 @@ QString AlbumControl::getDeviceName(const QString &devicePath)
return m_durlAndNameMap.value(devicePath);
}

QStringList AlbumControl::getDevicePicPaths(const QString &strPath)
DBImgInfoList fromDeviceAlbumInfoList(const QList<QPair<QString, ItemType>> &filePairList, const int &filterType)
{
// 若设备路径未被扫描,先扫描出所有图片/视频文件,设备容量越大,文件越大,扫描耗时越长
if (m_PhonePicFileMap.find(strPath) == m_PhonePicFileMap.end()) {
sltLoadMountFileList(strPath);
}

QStringList pathsList;
if (m_PhonePicFileMap.find(strPath) != m_PhonePicFileMap.end()) {
QStringList list = m_PhonePicFileMap.value(strPath);
for (QString path : list) {
pathsList << "file://" + path;
DBImgInfoList infoList;
for (auto fileItr = filePairList.begin(); fileItr != filePairList.end(); ++fileItr) {
if (ItemTypeNull != filterType && filterType != fileItr->second) {
continue;
}

DBImgInfo info;
info.filePath = fileItr->first;
info.itemType = fileItr->second;
info.pathHash = "";
info.remainDays = 0;

infoList << info;
}
return pathsList;
return infoList;
}

QVariantMap AlbumControl::getDeviceAlbumInfos(const QString &devicePath, const int &filterType)
void AlbumControl::loadDeviceAlbumInfoAsync(const QString &devicePath)
{
QVariantMap reMap;
QVariantList listVar;
QStringList list = getDevicePicPaths(devicePath);
QString title = devicePath;
for (QString path : list) {
QVariantMap tmpMap;
if (LibUnionImage_NameSpace::isImage(url2localPath(path))) {
if (filterType == 2) {
continue ;
}
tmpMap.insert("itemType", "pciture");
} else if (LibUnionImage_NameSpace::isVideo(url2localPath(path))) {
if (filterType == 1) {
continue ;
if (m_PhonePicFileMap.contains(devicePath)) {
return;
}

m_PhonePicFileMap.insert(devicePath, nullptr);
QThreadPool::globalInstance()->start([=](){
//获取所选文件类型过滤器
QStringList filters;
for (QString i : LibUnionImage_NameSpace::unionImageSupportFormat()) {
filters << "*." + i;
}
for (QString i : LibUnionImage_NameSpace::videoFiletypes()) {
filters << "*." + i;
}

//定义迭代器并设置过滤器,包括子目录:QDirIterator::Subdirectories
QDirIterator dir_iterator(devicePath,
filters,
QDir::Files/* | QDir::NoSymLinks*/,
QDirIterator::Subdirectories);

DeviceInfoPtr devicePtr = DeviceInfoPtr::create();
while (dir_iterator.hasNext()) {
dir_iterator.next();

ItemType type;
QString filePath = dir_iterator.filePath();
if (LibUnionImage_NameSpace::isImage(filePath)) {
type = ItemTypePic;
devicePtr->picCount++;
} else if (LibUnionImage_NameSpace::isVideo(filePath)) {
type = ItemTypeVideo;
devicePtr->videoCount++;
} else {
continue;
}
tmpMap.insert("itemType", "video");
} else {
tmpMap.insert("itemType", "other");

devicePtr->fileList.append(qMakePair(filePath, type));
}
tmpMap.insert("url", path);
tmpMap.insert("filePath", url2localPath(path));
tmpMap.insert("pathHash", "");
tmpMap.insert("remainDays", "");
listVar << tmpMap;
}
if (listVar.count() > 0) {
reMap.insert(title, listVar);
}
return reMap;

// GUI thread, notify update data
QMetaObject::invokeMethod(qApp, [=](){
m_PhonePicFileMap.insert(devicePath, devicePtr);

Q_EMIT deviceAlbumInfoLoadFinished(devicePath);
Q_EMIT deviceAlbumInfoCountChanged(devicePath, devicePtr->picCount, devicePtr->videoCount);
}, Qt::QueuedConnection);
});
}

DBImgInfoList AlbumControl::getDeviceAlbumInfos2(const QString &devicePath, const int &filterType)
DBImgInfoList AlbumControl::getDeviceAlbumInfoList(const QString &devicePath, const int &filterType, bool *loading)
{
DBImgInfoList infoList;

QStringList list = getDevicePicPaths(devicePath);
for (QString path : list) {
DBImgInfo info;
if (LibUnionImage_NameSpace::isImage(url2localPath(path))) {
if (filterType == ItemTypeVideo) {
continue ;
}
info.itemType = ItemTypePic;
} else if (LibUnionImage_NameSpace::isVideo(url2localPath(path))) {
if (filterType == ItemTypePic) {
continue ;
}
info.itemType = ItemTypeVideo;
} else {
continue;
auto itr = m_PhonePicFileMap.find(devicePath);
if (itr != m_PhonePicFileMap.end()) {
DeviceInfoPtr devicePtr = *(itr);
if (!devicePtr.isNull()) {
return fromDeviceAlbumInfoList(devicePtr->fileList, filterType);
}
info.filePath = url2localPath(path);
info.pathHash = "";
info.remainDays = 0;
infoList << info;
}

return infoList;
// Not load before, mark current device loading.
loadDeviceAlbumInfoAsync(devicePath);

if (loading) {
*loading = true;
}
return {};
}

int AlbumControl::getDeviceAlbumInfoConut(const QString &devicePath, const int &filterType)
void AlbumControl::getDeviceAlbumInfoCountAsync(const QString &devicePath)
{
int rePicVideoConut = 0;
QStringList list = getDevicePicPaths(devicePath);
for (QString path : list) {
QVariantMap tmpMap;
if (LibUnionImage_NameSpace::isImage(url2localPath(path))) {
if (filterType == ItemTypePic) {
rePicVideoConut++;
}
} else if (LibUnionImage_NameSpace::isVideo(url2localPath(path))) {
if (filterType == ItemTypeVideo) {
rePicVideoConut++;
}
auto itr = m_PhonePicFileMap.find(devicePath);
if (itr != m_PhonePicFileMap.end()) {
DeviceInfoPtr devicePtr = *(itr);
if (!devicePtr.isNull()) {
Q_EMIT deviceAlbumInfoCountChanged(devicePath, devicePtr->picCount, devicePtr->videoCount);
}
}
return rePicVideoConut;

// Not load before, mark current device loading.
loadDeviceAlbumInfoAsync(devicePath);
}

QList<int> AlbumControl::getPicVideoCountFromPaths(const QStringList &paths)
Expand Down
26 changes: 16 additions & 10 deletions src/src/albumControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,16 +241,13 @@ class AlbumControl : public QObject
//通过设备路径获得设备名称
Q_INVOKABLE QString getDeviceName(const QString &devicePath);

//获取设备的图片
Q_INVOKABLE QStringList getDevicePicPaths(const QString &path);
// Asynchronously load multimedia device data
void loadDeviceAlbumInfoAsync(const QString &devicePath);
DBImgInfoList getDeviceAlbumInfoList(const QString &devicePath, const int &filterType = 0, bool *loading = nullptr);
Q_SIGNAL void deviceAlbumInfoLoadFinished(const QString &devicePath);

//获得device路径
Q_INVOKABLE QVariantMap getDeviceAlbumInfos(const QString &devicePath, const int &filterType = 0);

Q_INVOKABLE DBImgInfoList getDeviceAlbumInfos2(const QString &devicePath, const int &filterType = 0);

//获得设备相册的图片和视频数量
Q_INVOKABLE int getDeviceAlbumInfoConut(const QString &devicePath, const int &filterType);
Q_INVOKABLE void getDeviceAlbumInfoCountAsync(const QString &devicePath);
Q_SIGNAL void deviceAlbumInfoCountChanged(const QString &devicePath, int picCount, int videoCount);

//手机照片导入 0为已导入,1-n为自定义相册
Q_INVOKABLE void importFromMountDevice(const QStringList &paths, const int &index = 0);
Expand Down Expand Up @@ -377,8 +374,10 @@ public slots:
//自动导入路径被删除
void slotMonitorDestroyed(int UID);

#if 0
//加载设备路径的数据
void sltLoadMountFileList(const QString &strPath);
#endif

void onDeviceRemoved(const QString &deviceKey, DeviceType type);
void onMounted(const QString &deviceKey, const QString &mountPoint, DeviceType type);
Expand Down Expand Up @@ -452,7 +451,14 @@ private :

QMap<QString, QString> m_durlAndNameMap; // 挂载点-设备名称map表
QMap<QString, QString> m_blkPath2DeviceNameMap; // 块设备id-名称map表
QMap<QString, QStringList> m_PhonePicFileMap; // 外部设备及其全部图片路径

struct DeviceInfo {
int picCount{0};
int videoCount{0};
QList<QPair<QString, ItemType>> fileList;
};
using DeviceInfoPtr = QSharedPointer<DeviceInfo>;
QMap<QString, DeviceInfoPtr> m_PhonePicFileMap; // 外部设备及其全部图片路径
std::atomic_bool m_couldRun;
bool m_bneedstop = false;
QMutex m_mutex;
Expand Down
Loading

0 comments on commit 4a0d5c0

Please sign in to comment.