mirror of
https://github.com/nextcloud/android.git
synced 2024-11-21 12:45:32 +03:00
Support for viewing tags
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
This commit is contained in:
parent
ffac056474
commit
f196bfd874
14 changed files with 1268 additions and 39 deletions
1137
app/schemas/com.nextcloud.client.database.NextcloudDatabase/69.json
Normal file
1137
app/schemas/com.nextcloud.client.database.NextcloudDatabase/69.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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?
|
||||
)
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -32,4 +32,6 @@ internal interface ListItemViewHolder : ListGridItemViewHolder {
|
|||
val lastModification: TextView
|
||||
val overflowMenu: ImageView
|
||||
val sharedAvatars: AvatarGroupLayout
|
||||
val tag: TextView
|
||||
val tagMore: TextView
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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-->
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue