Skip to content

Commit

Permalink
ignore image-media folders that have no-images _or_ seem to be music …
Browse files Browse the repository at this point in the history
…albums (just a single cover art image)

block detection notification and hide in lists

related to #3239

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
  • Loading branch information
AndyScherzinger committed Oct 14, 2020
1 parent 8b498f4 commit 3bb2edd
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ import com.nextcloud.client.preferences.AppPreferences
import com.nextcloud.client.preferences.AppPreferencesImpl
import com.owncloud.android.R
import com.owncloud.android.datamodel.ArbitraryDataProvider
import com.owncloud.android.datamodel.MediaFolderType
import com.owncloud.android.datamodel.MediaFoldersModel
import com.owncloud.android.datamodel.MediaProvider
import com.owncloud.android.datamodel.SyncedFolderProvider
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.ui.activity.ManageAccountsActivity.PENDING_FOR_REMOVAL
import com.owncloud.android.ui.activity.SyncedFoldersActivity
import com.owncloud.android.ui.notifications.NotificationUtils
import com.owncloud.android.utils.SyncedFolderUtils
import com.owncloud.android.utils.ThemeUtils
import java.util.ArrayList
import java.util.Random
Expand Down Expand Up @@ -133,7 +135,9 @@ class MediaFoldersDetectionWork constructor(
imageMediaFolder,
user.toPlatformAccount()
)
if (folder == null) {
if (folder == null &&
SyncedFolderUtils.isQualifyingMediaFolder(imageMediaFolder, MediaFolderType.IMAGE)
) {
val contentTitle = String.format(
resources.getString(R.string.new_media_folder_detected),
resources.getString(R.string.new_media_folder_photos)
Expand All @@ -143,7 +147,7 @@ class MediaFoldersDetectionWork constructor(
imageMediaFolder.substring(imageMediaFolder.lastIndexOf('/') + 1),
user,
imageMediaFolder,
1
MediaFolderType.IMAGE.id
)
}
}
Expand All @@ -162,7 +166,7 @@ class MediaFoldersDetectionWork constructor(
videoMediaFolder.substring(videoMediaFolder.lastIndexOf('/') + 1),
user,
videoMediaFolder,
2
MediaFolderType.VIDEO.id
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import com.owncloud.android.ui.dialog.parcel.SyncedFolderParcelable;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.PermissionUtil;
import com.owncloud.android.utils.SyncedFolderUtils;
import com.owncloud.android.utils.ThemeUtils;

import java.io.File;
Expand Down Expand Up @@ -378,13 +379,17 @@ private List<SyncedFolderDisplayItem> mergeFolderData(List<SyncedFolder> syncedF
SyncedFolder syncedFolder = syncedFoldersMap.get(mediaFolder.absolutePath + "-" + mediaFolder.type);
syncedFoldersMap.remove(mediaFolder.absolutePath + "-" + mediaFolder.type);

if (MediaFolderType.CUSTOM == syncedFolder.getType()) {
result.add(createSyncedFolderWithoutMediaFolder(syncedFolder));
} else {
result.add(createSyncedFolder(syncedFolder, mediaFolder));
if (syncedFolder != null && SyncedFolderUtils.isQualifyingMediaFolder(syncedFolder)) {
if (MediaFolderType.CUSTOM == syncedFolder.getType()) {
result.add(createSyncedFolderWithoutMediaFolder(syncedFolder));
} else {
result.add(createSyncedFolder(syncedFolder, mediaFolder));
}
}
} else {
result.add(createSyncedFolderFromMediaFolder(mediaFolder));
if (SyncedFolderUtils.isQualifyingMediaFolder(mediaFolder)) {
result.add(createSyncedFolderFromMediaFolder(mediaFolder));
}
}
}

Expand All @@ -399,7 +404,7 @@ private List<SyncedFolderDisplayItem> mergeFolderData(List<SyncedFolder> syncedF
private SyncedFolderDisplayItem createSyncedFolderWithoutMediaFolder(@NonNull SyncedFolder syncedFolder) {

File localFolder = new File(syncedFolder.getLocalPath());
File[] files = getFileList(localFolder);
File[] files = SyncedFolderUtils.getFileList(localFolder);
List<String> filePaths = getDisplayFilePathList(files);

return new SyncedFolderDisplayItem(
Expand Down Expand Up @@ -479,18 +484,6 @@ private SyncedFolderDisplayItem createSyncedFolderFromMediaFolder(@NonNull Media
false);
}

private File[] getFileList(File localFolder) {
File[] files = localFolder.listFiles(pathname -> !pathname.isDirectory());

if (files != null) {
Arrays.sort(files, (f1, f2) -> Long.compare(f1.lastModified(), f2.lastModified()));
} else {
files = new File[]{};
}

return files;
}

private List<String> getDisplayFilePathList(File... files) {
List<String> filePaths = null;

Expand Down
47 changes: 47 additions & 0 deletions src/main/java/com/owncloud/android/utils/FileUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Nextcloud Android client application
*
* @author Andy Scherzinger
* Copyright (C) 2020 Andy Scherzinger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.owncloud.android.utils;

import java.io.File;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

public final class FileUtil {
private static final int EMPTY_LENGTH = 0;

private FileUtil() {
// utility class -> private constructor
}

public static @NonNull String getFilenameFromPathString(@Nullable String filePath) {
if (filePath != null && filePath.length() > EMPTY_LENGTH) {
File file = new File(filePath);
if (file.isFile()) {
return file.getName();
} else {
return "";
}
} else {
return "";
}
}
}
202 changes: 202 additions & 0 deletions src/main/java/com/owncloud/android/utils/SyncedFolderUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
/*
* Nextcloud Android client application
*
* @author Andy Scherzinger
* Copyright (C) 2020 Andy Scherzinger
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.owncloud.android.utils;

import com.owncloud.android.datamodel.MediaFolder;
import com.owncloud.android.datamodel.MediaFolderType;
import com.owncloud.android.datamodel.SyncedFolder;

import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import androidx.annotation.Nullable;

/**
* Utility class with methods for processing synced folders.
*/
public final class SyncedFolderUtils {
private static final String[] DISQUALIFIED_MEDIA_DETECTION_SOURCE = new String[]{
"cover.jpg", "cover.jpeg",
"folder.jpg", "folder.jpeg"
};
private static final Set<String> DISQUALIFIED_MEDIA_DETECTION_SET =
new HashSet<>(Arrays.asList(DISQUALIFIED_MEDIA_DETECTION_SOURCE));
private static final int SINGLE_FILE = 1;

private SyncedFolderUtils() {
// utility class -> private constructor
}

/**
* analyzes a given media folder if its content qualifies for the folder to be handled as a media folder.
*
* @param mediaFolder media folder to analyse
* @return <code>true</code> if it qualifies as a media folder else <code>false</code>
*/
public static boolean isQualifyingMediaFolder(@Nullable MediaFolder mediaFolder) {
if (mediaFolder == null) {
return false;
}

// custom folders are always fine
if (MediaFolderType.CUSTOM == mediaFolder.type) {
return true;
}

// filter media folders

// no files
if (mediaFolder.numberOfFiles < SINGLE_FILE) {
return false;
} // music album (just one cover-art image)
else if (MediaFolderType.IMAGE == mediaFolder.type) {
return containsQualifiedImages(mediaFolder.filePaths);
}

return true;
}

/**
* analyzes a given synced folder if its content qualifies for the folder to be handled as a media folder.
*
* @param syncedFolder synced folder to analyse
* @return <code>true</code> if it qualifies as a media folder else <code>false</code>
*/
public static boolean isQualifyingMediaFolder(@Nullable SyncedFolder syncedFolder) {
if (syncedFolder == null) {
return false;
}

// custom folders are always fine
if (MediaFolderType.CUSTOM == syncedFolder.getType()) {
return true;
}

// filter media folders
File[] files = getFileList(new File(syncedFolder.getLocalPath()));

// no files
if (files.length < SINGLE_FILE) {
return false;
} // music album (just one cover-art image)
else if (MediaFolderType.IMAGE == syncedFolder.getType()) {
return containsQualifiedImages(files);
}

return true;
}

/**
* analyzes a given folder based on a path-string and type if its content qualifies for the folder to be handled as
* a media folder.
*
* @param folderPath String representation for a folder
* @param folderType type of the folder
* @return <code>true</code> if it qualifies as a media folder else <code>false</code>
*/
public static boolean isQualifyingMediaFolder(String folderPath, MediaFolderType folderType) {
// custom folders are always fine
if (MediaFolderType.CUSTOM == folderType) {
return true;
}

// filter media folders
File[] files = getFileList(new File(folderPath));

// no files
if (files.length < SINGLE_FILE) {
return false;
} // music album (just one cover-art image)
else if (MediaFolderType.IMAGE == folderType) {
return containsQualifiedImages(files);
}

return true;
}

/**
* check if given list contains images that qualify as auto upload relevant files.
*
* @param filePaths list of file paths
* @return <code>true</code> if at least one files qualifies as auto upload relevant else <code>false</code>
*/
private static boolean containsQualifiedImages(List<String> filePaths) {
for (String filePath : filePaths) {
if (isFileNameQualifiedForMediaDetection(FileUtil.getFilenameFromPathString(filePath))
&& MimeTypeUtil.isImage(MimeTypeUtil.getMimeTypeFromPath(filePath))) {
return true;
}
}

return false;
}

/**
* check if given list of files contains images that qualify as auto upload relevant files.
*
* @param files list of files
* @return <code>true</code> if at least one files qualifies as auto upload relevant else <code>false</code>
*/
private static boolean containsQualifiedImages(File... files) {
for (File file : files) {
if (isFileNameQualifiedForMediaDetection(file.getName()) && MimeTypeUtil.isImage(file)) {
return true;
}
}

return false;
}

/**
* check if given file is auto upload relevant files.
*
* @param fileName file name to be checked
* @return <code>true</code> if the file qualifies as auto upload relevant else <code>false</code>
*/
public static boolean isFileNameQualifiedForMediaDetection(String fileName) {
if (fileName != null) {
return !DISQUALIFIED_MEDIA_DETECTION_SET.contains(fileName.toLowerCase(Locale.ROOT));
} else {
return false;
}
}

/**
* return list of files for given folder.
*
* @param localFolder folder to scan
* @return sorted list of folder of given folder
*/
public static File[] getFileList(File localFolder) {
File[] files = localFolder.listFiles(pathname -> !pathname.isDirectory());

if (files != null) {
Arrays.sort(files, (f1, f2) -> Long.compare(f1.lastModified(), f2.lastModified()));
} else {
files = new File[]{};
}

return files;
}
}

0 comments on commit 3bb2edd

Please sign in to comment.