Support for viewing tags

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
tobiasKaminsky 2023-04-11 14:30:46 +02:00 committed by Andy Scherzinger
parent ffac056474
commit f196bfd874
No known key found for this signature in database
GPG Key ID: 6CADC7E3523C308B
14 changed files with 1268 additions and 39 deletions

File diff suppressed because it is too large Load Diff

View File

@ -48,20 +48,23 @@ class OCFileListFragmentStaticServerIT : AbstractIT() {
fun showFiles() {
val sut = testActivityRule.launchActivity(null)
val textFile = OCFile("/1.png")
textFile.mimeType = "image/png"
textFile.fileLength = 1024000
textFile.modificationTimestamp = 1188206955000
textFile.parentId = sut.storageManager.getFileByEncryptedRemotePath("/").fileId
sut.storageManager.saveFile(textFile)
OCFile("/1.png").apply {
mimeType = "image/png"
fileLength = 1024000
modificationTimestamp = 1188206955000
parentId = sut.storageManager.getFileByEncryptedRemotePath("/").fileId
sut.storageManager.saveFile(this)
}
val imageFile = OCFile("/image.png")
imageFile.mimeType = "image/png"
imageFile.isPreviewAvailable = false
imageFile.fileLength = 3072000
imageFile.modificationTimestamp = 746443755000
imageFile.parentId = sut.storageManager.getFileByEncryptedRemotePath("/").fileId
sut.storageManager.saveFile(imageFile)
OCFile("/image.png").apply {
mimeType = "image/png"
isPreviewAvailable = false
fileLength = 3072000
modificationTimestamp = 746443755000
parentId = sut.storageManager.getFileByEncryptedRemotePath("/").fileId
tags = listOf("Top secret")
sut.storageManager.saveFile(this)
}
OCFile("/video.mp4").apply {
mimeType = "video/mp4"
@ -69,6 +72,7 @@ class OCFileListFragmentStaticServerIT : AbstractIT() {
fileLength = 12092000
modificationTimestamp = 746143952000
parentId = sut.storageManager.getFileByEncryptedRemotePath("/").fileId
tags = listOf("Confidential", "+5")
sut.storageManager.saveFile(this)
}

View File

@ -117,5 +117,7 @@ data class FileEntity(
@ColumnInfo(name = ProviderTableMeta.FILE_LOCK_TIMEOUT)
val lockTimeout: Int?,
@ColumnInfo(name = ProviderTableMeta.FILE_LOCK_TOKEN)
val lockToken: String?
val lockToken: String?,
@ColumnInfo(name = ProviderTableMeta.FILE_TAGS)
val tags: String?
)

View File

@ -440,6 +440,7 @@ public class FileDataStorageManager {
*/
private ContentValues createContentValuesBase(OCFile fileOrFolder) {
final ContentValues cv = new ContentValues();
final Gson gson = new Gson();
cv.put(ProviderTableMeta.FILE_MODIFIED, fileOrFolder.getModificationTimestamp());
cv.put(ProviderTableMeta.FILE_MODIFIED_AT_LAST_SYNC_FOR_DATA, fileOrFolder.getModificationTimestampAtLastSyncForData());
cv.put(ProviderTableMeta.FILE_PARENT, fileOrFolder.getParentId());
@ -464,7 +465,8 @@ public class FileDataStorageManager {
cv.put(ProviderTableMeta.FILE_OWNER_ID, fileOrFolder.getOwnerId());
cv.put(ProviderTableMeta.FILE_OWNER_DISPLAY_NAME, fileOrFolder.getOwnerDisplayName());
cv.put(ProviderTableMeta.FILE_NOTE, fileOrFolder.getNote());
cv.put(ProviderTableMeta.FILE_SHAREES, new Gson().toJson(fileOrFolder.getSharees()));
cv.put(ProviderTableMeta.FILE_SHAREES, gson.toJson(fileOrFolder.getSharees()));
cv.put(ProviderTableMeta.FILE_TAGS, gson.toJson(fileOrFolder.getTags()));
cv.put(ProviderTableMeta.FILE_RICH_WORKSPACE, fileOrFolder.getRichWorkspace());
return cv;
}
@ -952,6 +954,20 @@ public class FileDataStorageManager {
}
}
String tags = fileEntity.getTags();
if (tags == null || tags.isEmpty() ||
JSON_NULL_STRING.equals(tags) || JSON_EMPTY_ARRAY.equals(tags)) {
ocFile.setTags(new ArrayList<>());
} else {
try {
String[] tagsArray = gson.fromJson(tags, String[].class);
ocFile.setTags(new ArrayList<>(Arrays.asList(tagsArray)));
} catch (JsonSyntaxException e) {
// ignore saved value due to api change
ocFile.setTags(new ArrayList<>());
}
}
String metadataSize = fileEntity.getMetadataSize();
// Surprisingly JSON deserialization causes significant overhead.
// Avoid it in common, trivial cases (null/empty).

View File

@ -114,6 +114,7 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
private String lockToken;
@Nullable
private ImageDimension imageDimension;
private List<String> tags;
/**
* URI to the local path of the file contents, if stored in the device; cached after first call to {@link
@ -966,4 +967,12 @@ public class OCFile implements Parcelable, Comparable<OCFile>, ServerFileInterfa
public ImageDimension getImageDimension() {
return imageDimension;
}
public List<String> getTags() {
return tags;
}
public void setTags(List<String> tags) {
this.tags = tags;
}
}

View File

@ -35,7 +35,7 @@ import java.util.List;
*/
public class ProviderMeta {
public static final String DB_NAME = "filelist";
public static final int DB_VERSION = 68;
public static final int DB_VERSION = 69;
private ProviderMeta() {
// No instance
@ -125,6 +125,7 @@ public class ProviderMeta {
public static final String FILE_LOCK_TIMESTAMP = "lock_timestamp";
public static final String FILE_LOCK_TIMEOUT = "lock_timeout";
public static final String FILE_LOCK_TOKEN = "lock_token";
public static final String FILE_TAGS = "tags";
public static final List<String> FILE_ALL_COLUMNS = Collections.unmodifiableList(Arrays.asList(
_ID,
@ -171,7 +172,8 @@ public class ProviderMeta {
FILE_LOCK_TIMESTAMP,
FILE_LOCK_TIMEOUT,
FILE_LOCK_TOKEN,
FILE_METADATA_SIZE));
FILE_METADATA_SIZE,
FILE_TAGS));
public static final String FILE_DEFAULT_SORT_ORDER = FILE_NAME + " collate nocase asc";
// Columns of ocshares table

View File

@ -32,4 +32,6 @@ internal interface ListItemViewHolder : ListGridItemViewHolder {
val lastModification: TextView
val overflowMenu: ImageView
val sharedAvatars: AvatarGroupLayout
val tag: TextView
val tagMore: TextView
}

View File

@ -415,6 +415,24 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
holder.getSharedAvatars().removeAllViews();
}
// tags
if (file.getTags().isEmpty()) {
holder.getTag().setVisibility(View.GONE);
holder.getTagMore().setVisibility(View.GONE);
} else {
holder.getTag().setVisibility(View.VISIBLE);
holder.getTag().setText(file.getTags().get(0));
if (file.getTags().size() > 1) {
holder.getTagMore().setVisibility(View.VISIBLE);
holder.getTagMore().setText(String.format(activity.getString(R.string.tags_more),
(file.getTags().size() - 1)));
} else {
holder.getTagMore().setVisibility(View.GONE);
}
}
// npe fix: looks like file without local storage path somehow get here
final String storagePath = file.getStoragePath();
if (onlyOnDevice && storagePath != null) {

View File

@ -48,6 +48,10 @@ internal class OCFileListItemViewHolder(private var binding: ListItemBinding) :
get() = binding.Filename
override val thumbnail: ImageView
get() = binding.thumbnailLayout.thumbnail
override val tag: TextView
get() = binding.tag
override val tagMore: TextView
get() = binding.tagMore
override fun showVideoOverlay() {
binding.thumbnailLayout.videoOverlay.visibility = View.VISIBLE

View File

@ -34,6 +34,7 @@ import com.owncloud.android.datamodel.FileDataStorageManager;
import com.owncloud.android.datamodel.OCFile;
import com.owncloud.android.lib.common.utils.Log_OC;
import com.owncloud.android.lib.resources.files.model.RemoteFile;
import com.owncloud.android.lib.resources.shares.ShareeUser;
import com.owncloud.android.ui.helpers.FileOperationsHelper;
import java.io.File;
@ -233,7 +234,7 @@ public final class FileStorageUtils {
file.setOwnerId(remote.getOwnerId());
file.setOwnerDisplayName(remote.getOwnerDisplayName());
file.setNote(remote.getNote());
file.setSharees(new ArrayList<>(Arrays.asList(remote.getSharees())));
file.setSharees(new ArrayList<ShareeUser>(Arrays.asList(remote.getSharees())));
file.setRichWorkspace(remote.getRichWorkspace());
file.setLocked(remote.isLocked());
file.setLockType(remote.getLockType());
@ -243,6 +244,7 @@ public final class FileStorageUtils {
file.setLockTimestamp(remote.getLockTimestamp());
file.setLockTimeout(remote.getLockTimeout());
file.setLockToken(remote.getLockToken());
file.setTags(new ArrayList<String>(Arrays.asList(remote.getTags())));
return file;
}

View File

@ -95,33 +95,65 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/file_size"
<com.google.android.material.chip.Chip
android:id="@+id/tag"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/placeholder_fileSize"
android:layout_marginEnd="@dimen/standard_eighth_margin"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size" />
android:textSize="@dimen/two_line_secondary_text_size"
app:chipStartPadding="@dimen/standard_eighth_margin"
app:chipEndPadding="@dimen/standard_eighth_margin"
android:checkable="false"
android:ellipsize="middle" />
<TextView
android:id="@+id/file_separator"
<com.google.android.material.chip.Chip
android:id="@+id/tag_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:paddingStart="@dimen/zero"
android:paddingEnd="@dimen/standard_quarter_padding"
android:text="@string/info_separator"
android:layout_marginStart="@dimen/standard_eighth_margin"
android:layout_marginEnd="@dimen/standard_eighth_margin"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size" />
android:textSize="@dimen/two_line_secondary_text_size"
app:chipStartPadding="@dimen/standard_eighth_margin"
app:chipEndPadding="@dimen/standard_eighth_margin"
app:chipBackgroundColor="@color/bg_default"
android:layout_weight="1" />
<TextView
android:id="@+id/last_mod"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:text="@string/placeholder_media_time"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size" />
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_weight="1">
<TextView
android:id="@+id/file_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/placeholder_fileSize"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size" />
<TextView
android:id="@+id/file_separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:paddingStart="@dimen/zero"
android:paddingEnd="@dimen/standard_quarter_padding"
android:text="@string/info_separator"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size" />
<TextView
android:id="@+id/last_mod"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="end"
android:text="@string/placeholder_media_time"
android:textColor="@color/list_item_lastmod_and_filesize_text"
android:textSize="@dimen/two_line_secondary_text_size" />
</LinearLayout>
</LinearLayout>
@ -161,9 +193,9 @@
<com.owncloud.android.ui.AvatarGroupLayout
android:id="@+id/sharedAvatars"
android:layout_width="100dp"
android:gravity="center_vertical"
android:layout_height="@dimen/file_icon_size"
android:contentDescription="@string/shared_avatar_desc"
android:gravity="center_vertical"
android:visibility="visible" />
<ImageView

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Beta indicator -->
<bool name="is_beta">false</bool>
<bool name="is_beta">true</bool>
<bool name="dev_version_direct_download_enabled">false</bool>
<!-- App name and other strings-->

View File

@ -1077,4 +1077,5 @@
<string name="document_scan_export_dialog_images">Multiple images</string>
<string name="download_cannot_create_file">Cannot create local file</string>
<string name="download_download_invalid_local_file_name">Invalid filename for local file</string>
<string name="tags_more">+%1$d</string>
</resources>

View File

@ -8,7 +8,7 @@ buildscript {
daggerVersion = "2.45"
markwonVersion = "4.6.2"
prismVersion = "2.0.0"
androidLibraryVersion = "master-SNAPSHOT"
androidLibraryVersion = "tags-SNAPSHOT"
mockitoVersion = "4.11.0"
mockitoKotlinVersion = "4.1.0"
mockkVersion = "1.13.3"