diff --git a/build.gradle b/build.gradle index 623df81f6617..b0551ab8335c 100644 --- a/build.gradle +++ b/build.gradle @@ -194,9 +194,9 @@ dependencies { // dependencies for app building implementation 'com.android.support:multidex:1.0.3' // implementation project('nextcloud-android-library') - genericImplementation "com.github.nextcloud:android-library:${androidLibraryVersion}" - gplayImplementation "com.github.nextcloud:android-library:${androidLibraryVersion}" - versionDevImplementation 'com.github.nextcloud:android-library:master-SNAPSHOT' // use always latest master + genericImplementation "com.github.nextcloud:android-library:filterActivities-SNAPSHOT" + gplayImplementation "com.github.nextcloud:android-library:filterActivities-SNAPSHOT" + versionDevImplementation 'com.github.nextcloud:android-library:filterActivities-SNAPSHOT' // use always latest master implementation "com.android.support:support-v4:${supportLibraryVersion}" implementation "com.android.support:design:${supportLibraryVersion}" implementation 'com.jakewharton:disklrucache:2.0.2' diff --git a/drawable_resources/ic_star.svg b/drawable_resources/ic_star.svg new file mode 100644 index 000000000000..40c0577e5915 --- /dev/null +++ b/drawable_resources/ic_star.svg @@ -0,0 +1 @@ + diff --git a/drawable_resources/ic_star_outline.svg b/drawable_resources/ic_star_outline.svg new file mode 100644 index 000000000000..638248c7c158 --- /dev/null +++ b/drawable_resources/ic_star_outline.svg @@ -0,0 +1 @@ + diff --git a/drawable_resources/ic_tag.svg b/drawable_resources/ic_tag.svg new file mode 100644 index 000000000000..fd1d1bf731cb --- /dev/null +++ b/drawable_resources/ic_tag.svg @@ -0,0 +1 @@ + diff --git a/scripts/lint/lint-results.txt b/scripts/lint/lint-results.txt index 0cc0a7f04705..820328a72cc0 100644 --- a/scripts/lint/lint-results.txt +++ b/scripts/lint/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 114 warnings + Lint Report: 113 warnings diff --git a/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 1c61db27147e..756471e553cb 100644 --- a/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -56,6 +56,7 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion; import com.owncloud.android.ui.TextDrawable; import com.owncloud.android.ui.adapter.DiskLruImageCache; +import com.owncloud.android.ui.fragment.FileFragment; import com.owncloud.android.ui.preview.PreviewImageFragment; import com.owncloud.android.utils.BitmapUtils; import com.owncloud.android.utils.ConnectivityUtils; @@ -208,17 +209,17 @@ public static Bitmap getBitmapFromDiskCache(String key) { } public static class ResizedImageGenerationTask extends AsyncTask { - private PreviewImageFragment previewImageFragment; + private FileFragment fileFragment; private FileDataStorageManager storageManager; private Account account; private WeakReference imageViewReference; private OCFile file; - public ResizedImageGenerationTask(PreviewImageFragment previewImageFragment, ImageView imageView, + public ResizedImageGenerationTask(FileFragment fileFragment, ImageView imageView, FileDataStorageManager storageManager, Account account) throws IllegalArgumentException { - this.previewImageFragment = previewImageFragment; + this.fileFragment = fileFragment; imageViewReference = new WeakReference<>(imageView); this.storageManager = storageManager; this.account = account; @@ -350,9 +351,13 @@ protected void onPostExecute(Bitmap bitmap) { } else { new Thread(() -> { if (ConnectivityUtils.isInternetWalled(MainApp.getAppContext())) { - previewImageFragment.setNoConnectionErrorMessage(); + if (fileFragment instanceof PreviewImageFragment) { + ((PreviewImageFragment) fileFragment).setNoConnectionErrorMessage(); + } } else { - previewImageFragment.setErrorPreviewMessage(); + if (fileFragment instanceof PreviewImageFragment) { + ((PreviewImageFragment) fileFragment).setErrorPreviewMessage(); + } } }).start(); diff --git a/src/main/java/com/owncloud/android/files/FileMenuFilter.java b/src/main/java/com/owncloud/android/files/FileMenuFilter.java index 4c9d07740c13..0ef99cada9ce 100644 --- a/src/main/java/com/owncloud/android/files/FileMenuFilter.java +++ b/src/main/java/com/owncloud/android/files/FileMenuFilter.java @@ -105,34 +105,46 @@ public void filter(Menu menu, boolean inSingleFileFragment) { filter(toShow, toHide, inSingleFileFragment); - MenuItem item; for (int i : toShow) { - item = menu.findItem(i); - if (item != null) { - item.setVisible(true); - item.setEnabled(true); - } + showMenuItem(menu.findItem(i)); } for (int i : toHide) { - item = menu.findItem(i); - if (item != null) { - item.setVisible(false); - item.setEnabled(false); - } + hideMenuItem(menu.findItem(i)); } } } - private void hideAll(Menu menu) { - MenuItem item; - for (int i = 0; i < menu.size(); i++) { - item = menu.getItem(i); + public static void hideAll(Menu menu) { + if (menu != null) { + for (int i = 0; i < menu.size(); i++) { + hideMenuItem(menu.getItem(i)); + } + } + } + + private static void hideMenuItem(MenuItem item) { + if (item != null) { item.setVisible(false); item.setEnabled(false); } } + private static void showMenuItem(MenuItem item) { + if (item != null) { + item.setVisible(true); + item.setEnabled(true); + } + } + + public static void hideMenuItems(MenuItem... items) { + if (items != null) { + for (MenuItem item : items) { + hideMenuItem(item); + } + } + } + /** * Performs the real filtering, to be applied in the {@link Menu} by the caller methods. * diff --git a/src/main/java/com/owncloud/android/ui/adapter/FileDetailTabAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/FileDetailTabAdapter.java new file mode 100644 index 000000000000..8b71890d99e3 --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/adapter/FileDetailTabAdapter.java @@ -0,0 +1,62 @@ +/* + * Nextcloud Android client application + * + * @author Andy Scherzinger + * Copyright (C) 2018 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 + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 . + */ + +package com.owncloud.android.ui.adapter; + +import android.accounts.Account; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; + +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.ui.fragment.FileDetailActivitiesFragment; +import com.owncloud.android.ui.fragment.FileDetailSharingFragment; + +/** + * File details pager adapter. + */ +public class FileDetailTabAdapter extends FragmentStatePagerAdapter { + private OCFile file; + private Account account; + + public FileDetailTabAdapter(FragmentManager fm, OCFile file, Account account) { + super(fm); + + this.file = file; + this.account = account; + } + + @Override + public Fragment getItem(int position) { + switch (position) { + case 0: + return FileDetailActivitiesFragment.newInstance(file, account); + case 1: + return FileDetailSharingFragment.newInstance(file, account); + default: + return null; + } + } + + @Override + public int getCount() { + return 2; + } +} diff --git a/src/main/java/com/owncloud/android/ui/adapter/ShareUserListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/ShareUserListAdapter.java index 17168192aab0..88d82b22fd3d 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/ShareUserListAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/ShareUserListAdapter.java @@ -22,6 +22,7 @@ import android.content.Context; import android.graphics.drawable.Drawable; +import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -32,7 +33,10 @@ import com.owncloud.android.R; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; +import com.owncloud.android.ui.TextDrawable; +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; /** @@ -43,6 +47,7 @@ public class ShareUserListAdapter extends ArrayAdapter { private Context mContext; private ArrayList mShares; private ShareUserAdapterListener mListener; + private float mAvatarRadiusDimension; public ShareUserListAdapter(Context context, int resource, ArrayListshares, ShareUserAdapterListener listener) { @@ -50,6 +55,8 @@ public ShareUserListAdapter(Context context, int resource, ArrayListsha mContext= context; mShares = shares; mListener = listener; + + mAvatarRadiusDimension = context.getResources().getDimension(R.dimen.standard_padding); } @Override @@ -67,32 +74,46 @@ public long getItemId(int position) { return 0; } + @NonNull @Override - public View getView(final int position, View convertView, ViewGroup parent) { - LayoutInflater inflator = (LayoutInflater) mContext - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - View view = inflator.inflate(R.layout.share_user_item, parent, false); + public View getView(final int position, View convertView, @NonNull ViewGroup parent) { + View view = convertView; + if (view == null) { + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + view = inflater.inflate(R.layout.share_user_item, parent, false); + } if (mShares != null && mShares.size() > position) { OCShare share = mShares.get(position); - TextView userName = (TextView) view.findViewById(R.id.userOrGroupName); - ImageView iconView = (ImageView) view.findViewById(R.id.icon); - final ImageView editShareButton = (ImageView) view.findViewById(R.id.editShareButton); - final ImageView unshareButton = (ImageView) view.findViewById(R.id.unshareButton); + TextView userName = view.findViewById(R.id.userOrGroupName); + ImageView icon = view.findViewById(R.id.icon); + final ImageView editShareButton = view.findViewById(R.id.editShareButton); + final ImageView unshareButton = view.findViewById(R.id.unshareButton); String name = share.getSharedWithDisplayName(); - Drawable icon = getContext().getResources().getDrawable(R.drawable.ic_user); if (share.getShareType() == ShareType.GROUP) { name = getContext().getString(R.string.share_group_clarification, name); - icon = getContext().getResources().getDrawable(R.drawable.ic_group); + try { + icon.setImageDrawable(TextDrawable.createNamedAvatar(name, mAvatarRadiusDimension)); + } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + icon.setImageResource(R.drawable.ic_group); + } } else if (share.getShareType() == ShareType.EMAIL) { name = getContext().getString(R.string.share_email_clarification, name); - icon = getContext().getResources().getDrawable(R.drawable.ic_email); - editShareButton.setVisibility(View.INVISIBLE); + try { + icon.setImageDrawable(TextDrawable.createNamedAvatar(name, mAvatarRadiusDimension)); + } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + icon.setImageResource(R.drawable.ic_email); + } + } else { + try { + icon.setImageDrawable(TextDrawable.createNamedAvatar(name, mAvatarRadiusDimension)); + } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + icon.setImageResource(R.drawable.ic_user); + } } userName.setText(name); - iconView.setImageDrawable(icon); /// bind listener to edit privileges editShareButton.setOnClickListener(new View.OnClickListener() { diff --git a/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java b/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java index 0f321248f5c1..6d7d120fbede 100644 --- a/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java +++ b/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java @@ -32,7 +32,10 @@ import com.owncloud.android.R; import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.lib.resources.shares.ShareType; +import com.owncloud.android.ui.TextDrawable; +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; /** @@ -42,11 +45,14 @@ public class UserListAdapter extends ArrayAdapter { private Context mContext; private ArrayList mShares; + private float mAvatarRadiusDimension; public UserListAdapter(Context context, int resource, ArrayList shares) { super(context, resource); mContext = context; mShares = shares; + + mAvatarRadiusDimension = context.getResources().getDimension(R.dimen.standard_padding); } @Override @@ -75,15 +81,29 @@ public long getItemId(int position) { if (mShares != null && mShares.size() > position) { OCShare share = mShares.get(position); - TextView userName = (TextView) view.findViewById(R.id.userOrGroupName); - ImageView icon = (ImageView) view.findViewById(R.id.userIcon); + TextView userName = view.findViewById(R.id.userOrGroupName); + ImageView icon = view.findViewById(R.id.userIcon); String name = share.getSharedWithDisplayName(); if (share.getShareType() == ShareType.GROUP) { name = getContext().getString(R.string.share_group_clarification, name); - icon.setImageResource(R.drawable.ic_group); + try { + icon.setImageDrawable(TextDrawable.createNamedAvatar(name, mAvatarRadiusDimension)); + } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + icon.setImageResource(R.drawable.ic_group); + } } else if (share.getShareType() == ShareType.EMAIL) { name = getContext().getString(R.string.share_email_clarification, name); - icon.setImageResource(R.drawable.ic_email); + try { + icon.setImageDrawable(TextDrawable.createNamedAvatar(name, mAvatarRadiusDimension)); + } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + icon.setImageResource(R.drawable.ic_email); + } + } else { + try { + icon.setImageDrawable(TextDrawable.createNamedAvatar(name, mAvatarRadiusDimension)); + } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) { + icon.setImageResource(R.drawable.ic_user); + } } userName.setText(name); diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java new file mode 100644 index 000000000000..bc8c3a93bb46 --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailActivitiesFragment.java @@ -0,0 +1,327 @@ +/* + * Nextcloud Android client application + * + * @author Andy Scherzinger + * Copyright (C) 2018 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 + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 . + */ + +package com.owncloud.android.ui.fragment; + +import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.Context; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.owncloud.android.MainApp; +import com.owncloud.android.R; +import com.owncloud.android.authentication.AccountUtils; +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.lib.common.OwnCloudAccount; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.utils.Log_OC; +import com.owncloud.android.lib.resources.activities.GetRemoteActivitiesOperation; +import com.owncloud.android.lib.resources.activities.models.RichObject; +import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.ui.adapter.ActivityListAdapter; +import com.owncloud.android.ui.interfaces.ActivityListInterface; +import com.owncloud.android.utils.ThemeUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import butterknife.BindString; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.Unbinder; + +public class FileDetailActivitiesFragment extends Fragment implements ActivityListInterface { + private static final String TAG = FileDetailActivitiesFragment.class.getSimpleName(); + + private static final String ARG_FILE = "FILE"; + private static final String ARG_ACCOUNT = "ACCOUNT"; + + private ActivityListAdapter adapter; + private Unbinder unbinder; + private OwnCloudClient ownCloudClient; + + private OCFile file; + private Account account; + + private String nextPageUrl; + private boolean isLoadingActivities; + + @BindView(R.id.empty_list_view) + public LinearLayout emptyContentContainer; + + @BindView(R.id.swipe_containing_list) + public SwipeRefreshLayout swipeListRefreshLayout; + + @BindView(R.id.swipe_containing_empty) + public SwipeRefreshLayout swipeEmptyListRefreshLayout; + + @BindView(R.id.empty_list_view_text) + public TextView emptyContentMessage; + + @BindView(R.id.empty_list_view_headline) + public TextView emptyContentHeadline; + + @BindView(R.id.empty_list_icon) + public ImageView emptyContentIcon; + + @BindView(R.id.empty_list_progress) + public ProgressBar emptyContentProgressBar; + + @BindView(android.R.id.list) + public RecyclerView recyclerView; + + @BindString(R.string.activities_no_results_headline) + public String noResultsHeadline; + + @BindString(R.string.activities_no_results_message) + public String noResultsMessage; + + public static FileDetailActivitiesFragment newInstance(OCFile file, Account account) { + FileDetailActivitiesFragment fragment = new FileDetailActivitiesFragment(); + Bundle args = new Bundle(); + args.putParcelable(ARG_FILE, file); + args.putParcelable(ARG_ACCOUNT, account); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, + Bundle savedInstanceState) { + + file = getArguments().getParcelable(ARG_FILE); + account = getArguments().getParcelable(ARG_ACCOUNT); + + if (savedInstanceState != null) { + file = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE); + account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT); + } + + View view = inflater.inflate(R.layout.file_details_activities_fragment, container, false); + unbinder = ButterKnife.bind(this, view); + + setupView(); + + onCreateSwipeToRefresh(swipeEmptyListRefreshLayout); + onCreateSwipeToRefresh(swipeListRefreshLayout); + + fetchAndSetData(null); + + swipeListRefreshLayout.setOnRefreshListener(() -> { + setLoadingMessage(); + if (swipeListRefreshLayout != null && swipeListRefreshLayout.isRefreshing()) { + swipeListRefreshLayout.setRefreshing(false); + } + fetchAndSetData(null); + } + ); + + swipeEmptyListRefreshLayout.setOnRefreshListener(() -> { + setLoadingMessage(); + if (swipeEmptyListRefreshLayout != null && swipeEmptyListRefreshLayout.isRefreshing()) { + swipeEmptyListRefreshLayout.setRefreshing(false); + } + fetchAndSetData(null); + } + ); + + return view; + } + + private void setLoadingMessage() { + emptyContentHeadline.setText(R.string.file_list_loading); + emptyContentMessage.setText(""); + + emptyContentIcon.setVisibility(View.GONE); + emptyContentProgressBar.setVisibility(View.VISIBLE); + } + + @Override + public void onDestroy() { + super.onDestroy(); + unbinder.unbind(); + } + + private void setupView() { + FileDataStorageManager storageManager = new FileDataStorageManager(account, getActivity().getContentResolver()); + emptyContentProgressBar.getIndeterminateDrawable().setColorFilter(ThemeUtils.primaryAccentColor(getContext()), + PorterDuff.Mode.SRC_IN); + emptyContentIcon.setImageDrawable(getResources().getDrawable(R.drawable.ic_activity_light_grey)); + + adapter = new ActivityListAdapter(getContext(), this, storageManager); + recyclerView.setAdapter(adapter); + + LinearLayoutManager layoutManager = new LinearLayoutManager(getContext()); + + recyclerView.setLayoutManager(layoutManager); + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + + int visibleItemCount = recyclerView.getChildCount(); + int totalItemCount = layoutManager.getItemCount(); + int firstVisibleItemIndex = layoutManager.findFirstVisibleItemPosition(); + + // synchronize loading state when item count changes + if (!isLoadingActivities && (totalItemCount - visibleItemCount) <= (firstVisibleItemIndex + 5) + && nextPageUrl != null && !nextPageUrl.isEmpty()) { + // Almost reached the end, continue to load new activities + fetchAndSetData(nextPageUrl); + } + } + }); + } + + /** + * @param pageUrl String + */ + private void fetchAndSetData(String pageUrl) { + final Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext()); + final Context context = MainApp.getAppContext(); + + Thread t = new Thread(() -> { + OwnCloudAccount ocAccount; + try { + ocAccount = new OwnCloudAccount(currentAccount, context); + ownCloudClient = OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, MainApp.getAppContext()); + ownCloudClient.setOwnCloudVersion(AccountUtils.getServerVersion(currentAccount)); + isLoadingActivities = true; + + GetRemoteActivitiesOperation getRemoteNotificationOperation = new GetRemoteActivitiesOperation( + file.getLocalId()); + + if (pageUrl != null) { + getRemoteNotificationOperation.setNextUrl(pageUrl); + } + + Log_OC.d(TAG, "BEFORE getRemoteActivitiesOperation.execute"); + final RemoteOperationResult result = getRemoteNotificationOperation.execute(ownCloudClient); + + if (result.isSuccess() && result.getData() != null) { + final ArrayList data = result.getData(); + final ArrayList activities = (ArrayList) data.get(0); + nextPageUrl = (String) data.get(1); + + getActivity().runOnUiThread(() -> { + populateList(activities, ownCloudClient, pageUrl == null); + if (activities.size() > 0) { + swipeEmptyListRefreshLayout.setVisibility(View.GONE); + swipeListRefreshLayout.setVisibility(View.VISIBLE); + } else { + setEmptyContent(noResultsHeadline, noResultsMessage); + swipeListRefreshLayout.setVisibility(View.GONE); + swipeEmptyListRefreshLayout.setVisibility(View.VISIBLE); + } + isLoadingActivities = false; + }); + } else { + Log_OC.d(TAG, result.getLogMessage()); + // show error + String logMessage = result.getLogMessage(); + if (result.getHttpCode() == 304) { + logMessage = noResultsMessage; + } + final String finalLogMessage = logMessage; + getActivity().runOnUiThread(() -> { + setEmptyContent(noResultsHeadline, finalLogMessage); + isLoadingActivities = false; + //setIndeterminate(isLoadingActivities); + }); + } + + hideRefreshLayoutLoader(); + } catch (com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException e) { + Log_OC.e(TAG, "Account not found", e); + } catch (IOException e) { + Log_OC.e(TAG, "IO error", e); + } catch (OperationCanceledException e) { + Log_OC.e(TAG, "Operation has been canceled", e); + } catch (AuthenticatorException e) { + Log_OC.e(TAG, "Authentication Exception", e); + } + } + ); + + t.start(); + } + + private void populateList(List activities, OwnCloudClient mClient, boolean clear) { + adapter.setActivityItems(activities, mClient, clear); + } + + private void setEmptyContent(String headline, String message) { + if (emptyContentContainer != null && emptyContentMessage != null) { + emptyContentHeadline.setText(headline); + emptyContentMessage.setText(message); + + emptyContentProgressBar.setVisibility(View.GONE); + emptyContentIcon.setVisibility(View.VISIBLE); + } + } + + private void hideRefreshLayoutLoader() { + getActivity().runOnUiThread(() -> { + if (swipeListRefreshLayout != null) { + swipeListRefreshLayout.setRefreshing(false); + } + if (swipeEmptyListRefreshLayout != null) { + swipeEmptyListRefreshLayout.setRefreshing(false); + } + isLoadingActivities = false; + //setIndeterminate(isLoadingActivities); + }); + } + + protected void onCreateSwipeToRefresh(SwipeRefreshLayout refreshLayout) { + int primaryColor = ThemeUtils.primaryColor(getContext()); + int darkColor = ThemeUtils.primaryDarkColor(getContext()); + int accentColor = ThemeUtils.primaryAccentColor(getContext()); + + // Colors in animations + refreshLayout.setColorSchemeColors(accentColor, primaryColor, darkColor); + } + + @Override + public void onActivityClicked(RichObject richObject) { + // TODO implement activity click + } +} diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 168938d175e8..e6e8477ac7ae 100644 --- a/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -23,20 +23,20 @@ import android.accounts.Account; import android.graphics.Bitmap; +import android.os.Build; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; -import android.support.v7.widget.SwitchCompat; +import android.support.design.widget.TabLayout; +import android.support.v4.view.ViewPager; import android.view.LayoutInflater; import android.view.Menu; -import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.CompoundButton; import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.ListView; +import android.widget.PopupMenu; import android.widget.ProgressBar; import android.widget.TextView; @@ -50,10 +50,10 @@ import com.owncloud.android.files.services.FileUploader.FileUploaderBinder; import com.owncloud.android.lib.common.network.OnDatatransferProgressListener; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.lib.resources.shares.OCShare; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; -import com.owncloud.android.ui.adapter.UserListAdapter; +import com.owncloud.android.ui.activity.ToolbarActivity; +import com.owncloud.android.ui.adapter.FileDetailTabAdapter; import com.owncloud.android.ui.dialog.RemoveFilesDialogFragment; import com.owncloud.android.ui.dialog.RenameFileDialogFragment; import com.owncloud.android.utils.AnalyticsUtils; @@ -62,23 +62,21 @@ import com.owncloud.android.utils.ThemeUtils; import java.lang.ref.WeakReference; -import java.util.ArrayList; /** * This Fragment is used to display the details about a file. */ -public class FileDetailFragment extends FileFragment implements OnClickListener, - CompoundButton.OnCheckedChangeListener { +public class FileDetailFragment extends FileFragment implements OnClickListener { - private int mLayout; - private View mView; - private Account mAccount; + private int layout; + private View view; + private ImageView previewImage; + private ProgressBar toolbarProgressBar; + private boolean previewLoaded; + private Account account; - public ProgressListener mProgressListener; - - // to show share with users/groups info - private ArrayList mShares; + public ProgressListener progressListener; private static final String TAG = FileDetailFragment.class.getSimpleName(); public static final String FTAG_CONFIRMATION = "REMOVE_CONFIRMATION_FRAGMENT"; @@ -115,9 +113,9 @@ public static FileDetailFragment newInstance(OCFile fileToDetail, Account accoun */ public FileDetailFragment() { super(); - mAccount = null; - mLayout = R.layout.file_details_empty; - mProgressListener = null; + account = null; + layout = R.layout.file_details_empty; + progressListener = null; } @Override @@ -126,6 +124,18 @@ public void onResume() { if (getActivity() != null) { AnalyticsUtils.setCurrentScreenName(getActivity(), SCREEN_NAME, TAG); } + + if (previewImage != null && MimeTypeUtil.isImage(getFile()) && previewLoaded) { + activatePreviewImage(); + } + } + + private void activatePreviewImage() { + previewImage.setVisibility(View.VISIBLE); + toolbarProgressBar.setVisibility(View.GONE); + ((ToolbarActivity) getActivity()).getSupportActionBar().setTitle(null); + ((ToolbarActivity) getActivity()).getSupportActionBar().setBackgroundDrawable(null); + makeStatusBarBlack(); } @Override @@ -135,45 +145,141 @@ public void onActivityCreated(Bundle savedInstanceState) { } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { setFile(getArguments().getParcelable(ARG_FILE)); - mAccount = getArguments().getParcelable(ARG_ACCOUNT); + account = getArguments().getParcelable(ARG_ACCOUNT); if (savedInstanceState != null) { setFile(savedInstanceState.getParcelable(FileActivity.EXTRA_FILE)); - mAccount = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT); + account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT); } - if (getFile() != null && mAccount != null) { - mLayout = R.layout.file_details_fragment; + toolbarProgressBar = getActivity().findViewById(R.id.progressBar); + + if (getFile() != null && account != null) { + layout = R.layout.file_details_fragment; } - mView = inflater.inflate(mLayout, null); + view = inflater.inflate(layout, null); - if (mLayout == R.layout.file_details_fragment) { - int accentColor = ThemeUtils.primaryAccentColor(getContext()); - SwitchCompat favoriteToggle = mView.findViewById(R.id.fdFavorite); - favoriteToggle.setOnCheckedChangeListener(this); - ThemeUtils.tintSwitch(favoriteToggle, accentColor, false); - ProgressBar progressBar = mView.findViewById(R.id.fdProgressBar); + if (layout == R.layout.file_details_fragment) { + ProgressBar progressBar = view.findViewById(R.id.fdProgressBar); ThemeUtils.colorHorizontalProgressBar(progressBar, ThemeUtils.primaryAccentColor(getContext())); - mProgressListener = new ProgressListener(progressBar); - mView.findViewById(R.id.fdCancelBtn).setOnClickListener(this); - ((TextView)mView.findViewById(R.id.fdShareTitle)).setTextColor(accentColor); - ((TextView)mView.findViewById(R.id.fdShareWithUsersTitle)).setTextColor(accentColor); + progressListener = new ProgressListener(progressBar); + view.findViewById(R.id.fdCancelBtn).setOnClickListener(this); + view.findViewById(R.id.fdFavorite).setOnClickListener(this); + view.findViewById(R.id.overflow_menu).setOnClickListener(this); + previewImage = getActivity().findViewById(R.id.preview_image); + // TODO use whenever we switch to use glide for preview images + /* + if (getFile() != null && account != null && MimeTypeUtil.isImage(getFile())) { + setHeaderImage(); + } + */ } updateFileDetails(false, false); - return mView; + return view; + } + // TODO use whenever we switch to use glide for preview images + /* + private void setHeaderImage() { + if (mContainerActivity.getStorageManager().getCapability(account.name) + .getServerBackground() != null && previewImage != null) { + + String background = mContainerActivity.getStorageManager().getCapability(account.name).getServerBackground(); + + int primaryColor = ThemeUtils.primaryColor(account, getContext()); + + if (URLUtil.isValidUrl(background)) { + // background image + SimpleTarget target = new SimpleTarget() { + @Override + public void onResourceReady(Drawable resource, GlideAnimation glideAnimation) { + Drawable[] drawables = {new ColorDrawable(primaryColor), resource}; + LayerDrawable layerDrawable = new LayerDrawable(drawables); + previewImage.setImageDrawable(layerDrawable); + previewImage.setVisibility(View.VISIBLE); + ((ToolbarActivity) getActivity()).getSupportActionBar().setTitle(null); + ((ToolbarActivity) getActivity()).getSupportActionBar().setBackgroundDrawable(null); + toolbarProgressBar.setVisibility(View.GONE); + previewLoaded = true; + } + + @Override + public void onLoadFailed(Exception e, Drawable errorDrawable) { + previewImage.setVisibility(View.GONE); + toolbarProgressBar.setVisibility(View.VISIBLE); + } + }; + + Glide.with(this) + .load(background) + .centerCrop() + .placeholder(R.drawable.background) + .error(R.drawable.background) + .crossFade() + .into(target); + } else { + // hide image + previewImage.setVisibility(View.GONE); + toolbarProgressBar.setVisibility(View.VISIBLE); + } + } + } + */ + + public void onOverflowIconClicked(View view) { + PopupMenu popup = new PopupMenu(getActivity(), view); + popup.inflate(R.menu.file_actions_menu); + prepareOptionsMenu(popup.getMenu()); + + popup.setOnMenuItemClickListener(item -> { + return optionsItemSelected(item); + }); + popup.show(); + } + + private void setupViewPager(View view) { + TabLayout tabLayout = view.findViewById(R.id.tab_layout); + tabLayout.removeAllTabs(); + + tabLayout.addTab(tabLayout.newTab().setText(R.string.drawer_item_activities)); + tabLayout.addTab(tabLayout.newTab().setText(R.string.share_dialog_title)); + + tabLayout.setTabGravity(TabLayout.GRAVITY_FILL); + tabLayout.setSelectedTabIndicatorColor(ThemeUtils.primaryAccentColor(getContext())); + + final ViewPager viewPager = view.findViewById(R.id.pager); + final FileDetailTabAdapter adapter = new FileDetailTabAdapter + (getFragmentManager(), getFile(), account); + viewPager.setAdapter(adapter); + viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout)); + tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + viewPager.setCurrentItem(tab.getPosition()); + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + // unused at the moment + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + // unused at the moment + } + }); } @Override - public void onSaveInstanceState(Bundle outState) { + public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putParcelable(FileActivity.EXTRA_FILE, getFile()); - outState.putParcelable(FileActivity.EXTRA_ACCOUNT, mAccount); + outState.putParcelable(FileActivity.EXTRA_ACCOUNT, account); } @Override @@ -185,33 +291,30 @@ public void onStart() { @Override public void onStop() { leaveTransferProgress(); + if (previewImage != null) { + previewImage.setVisibility(View.GONE); + toolbarProgressBar.setVisibility(View.VISIBLE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + getActivity().getWindow().setStatusBarColor(ThemeUtils.primaryDarkColor(getContext())); + } + } + super.onStop(); } - @Override public View getView() { - return super.getView() == null ? mView : super.getView(); - } - - - /** - * {@inheritDoc} - */ - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.file_actions_menu, menu); + return super.getView() == null ? view : super.getView(); } - - /** - * {@inheritDoc} - */ @Override public void onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); + FileMenuFilter.hideAll(menu); + } + + private void prepareOptionsMenu(Menu menu) { if (mContainerActivity.getStorageManager() != null) { FileMenuFilter mf = new FileMenuFilter( getFile(), @@ -223,94 +326,33 @@ public void onPrepareOptionsMenu(Menu menu) { mf.filter(menu, true); } - // additional restriction for this fragment - MenuItem item = menu.findItem(R.id.action_see_details); - if (item != null) { - item.setVisible(false); - item.setEnabled(false); - } - - // additional restriction for this fragment - item = menu.findItem(R.id.action_select_all); - if (item != null) { - item.setVisible(false); - item.setEnabled(false); - } - - // additional restriction for this fragment - item = menu.findItem(R.id.action_move); - if (item != null) { - item.setVisible(false); - item.setEnabled(false); - } - - // additional restriction for this fragment - item = menu.findItem(R.id.action_copy); - if (item != null) { - item.setVisible(false); - item.setEnabled(false); - } - - // additional restriction for this fragment - item = menu.findItem(R.id.action_favorite); - if (item != null) { - item.setVisible(false); - item.setEnabled(false); - } - - // additional restriction for this fragment - item = menu.findItem(R.id.action_unset_favorite); - if (item != null) { - item.setVisible(false); - item.setEnabled(false); - } - - // additional restriction for this fragment - item = menu.findItem(R.id.action_search); - if (item != null) { - item.setVisible(false); - item.setEnabled(false); - } - - - Boolean dualPane = getResources().getBoolean(R.bool.large_land_layout); - - item = menu.findItem(R.id.action_switch_view); - if (item != null && !dualPane){ - item.setVisible(false); - item.setEnabled(false); - } - - item = menu.findItem(R.id.action_sync_account); - if (item != null && !dualPane) { - item.setVisible(false); - item.setEnabled(false); - } + // restriction for this fragment + FileMenuFilter.hideMenuItems( + menu.findItem(R.id.action_see_details), + menu.findItem(R.id.action_select_all), + menu.findItem(R.id.action_move), + menu.findItem(R.id.action_copy), + menu.findItem(R.id.action_favorite), + menu.findItem(R.id.action_unset_favorite), + menu.findItem(R.id.action_search) + ); - item = menu.findItem(R.id.action_sort); - if (item != null && !dualPane) { - item.setVisible(false); - item.setEnabled(false); + // dual pane restrictions + if (!getResources().getBoolean(R.bool.large_land_layout)){ + FileMenuFilter.hideMenuItems( + menu.findItem(R.id.action_switch_view), + menu.findItem(R.id.action_sync_account), + menu.findItem(R.id.action_sort) + ); } - item = menu.findItem(R.id.action_send_share_file); - if (item != null) { - ThemeUtils.tintDrawable(item.getIcon(), ThemeUtils.fontColor(getContext())); - item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - if (getFile().isSharedWithMe() && !getFile().canReshare()) { - // additional restriction for this fragment - - item.setVisible(false); - item.setEnabled(false); - } + // share restrictions + if (getFile().isSharedWithMe() && !getFile().canReshare()) { + FileMenuFilter.hideMenuItems(menu.findItem(R.id.action_send_share_file)); } } - /** - * {@inheritDoc} - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { + public boolean optionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_send_share_file: { if(getFile().isSharedWithMe() && !getFile().canReshare()){ @@ -347,6 +389,14 @@ public boolean onOptionsItemSelected(MenuItem item) { mContainerActivity.getFileOperationsHelper().syncFile(getFile()); return true; } + case R.id.action_keep_files_offline: { + mContainerActivity.getFileOperationsHelper().toggleOfflineFile(getFile(), true); + return true; + } + case R.id.action_unset_keep_files_offline: { + mContainerActivity.getFileOperationsHelper().toggleOfflineFile(getFile(), false); + return true; + } default: return super.onOptionsItemSelected(item); } @@ -359,28 +409,39 @@ public void onClick(View v) { ((FileDisplayActivity) mContainerActivity).cancelTransference(getFile()); break; } + case R.id.fdFavorite: { + if (getFile().getIsFavorite()) { + ((ImageView)getView().findViewById(R.id.fdFavorite)). + setImageDrawable(getResources() + .getDrawable(R.drawable.ic_star_outline)); + mContainerActivity.getFileOperationsHelper().toggleFavoriteFile(getFile(), false); + } else { + ((ImageView)getView().findViewById(R.id.fdFavorite)) + .setImageDrawable(getResources() + .getDrawable(R.drawable.ic_star)); + mContainerActivity.getFileOperationsHelper().toggleFavoriteFile(getFile(), true); + } + break; + } + case R.id.overflow_menu: { + onOverflowIconClicked(v); + break; + } default: Log_OC.e(TAG, "Incorrect view clicked!"); break; } } - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - SwitchCompat favSwitch = getView().findViewById(R.id.fdFavorite); - mContainerActivity.getFileOperationsHelper().toggleOfflineFile(getFile(), favSwitch.isChecked()); - } - /** * Check if the fragment was created with an empty layout. An empty fragment can't show file details, must be replaced. * * @return True when the fragment was created with the empty layout. */ public boolean isEmpty() { - return (mLayout == R.layout.file_details_empty || getFile() == null || mAccount == null); + return (layout == R.layout.file_details_empty || getFile() == null || account == null); } - /** * Use this method to signal this Activity that it shall update its view. * @@ -388,13 +449,13 @@ public boolean isEmpty() { */ public void updateFileDetails(OCFile file, Account ocAccount) { setFile(file); - mAccount = ocAccount; + account = ocAccount; updateFileDetails(false, false); } /** * Updates the view with all relevant details about that file. - *

+ * * TODO Remove parameter when the transferring state of files is kept in database. * * @param transferring Flag signaling if the file should be considered as downloading or uploading, @@ -419,22 +480,20 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setFilename(file.getFileName()); setFiletype(file); setFilesize(file.getFileLength()); - setTimeModified(file.getModificationTimestamp()); - SwitchCompat favSwitch = getView().findViewById(R.id.fdFavorite); - favSwitch.setChecked(file.isAvailableOffline()); - - setShareByLinkInfo(file.isSharedViaLink()); - - setShareWithUserInfo(); + if (file.getIsFavorite()) { + ((ImageView)getView().findViewById(R.id.fdFavorite)).setImageDrawable(getResources().getDrawable(R.drawable.ic_star)); + } else { + ((ImageView)getView().findViewById(R.id.fdFavorite)).setImageDrawable(getResources().getDrawable(R.drawable.ic_star_outline)); + } // configure UI for depending upon local state of the file FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder(); if (transferring || - (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, file)) || - (uploaderBinder != null && uploaderBinder.isUploading(mAccount, file)) + (downloaderBinder != null && downloaderBinder.isDownloading(account, file)) || + (uploaderBinder != null && uploaderBinder.isUploading(account, file)) ) { setButtonsForTransferring(); @@ -448,6 +507,9 @@ public void updateFileDetails(boolean transferring, boolean refresh) { setButtonsForRemote(); } } + + setupViewPager(getView()); + getView().invalidate(); } @@ -457,10 +519,9 @@ public void updateFileDetails(boolean transferring, boolean refresh) { * @return 'True' when the fragment is ready to show details of a file */ private boolean readyToShow() { - return (getFile() != null && mAccount != null && mLayout == R.layout.file_details_fragment); + return (getFile() != null && account != null && layout == R.layout.file_details_fragment); } - /** * Updates the filename in view * @@ -479,48 +540,75 @@ private void setFilename(String filename) { */ private void setFiletype(OCFile file) { ImageView iv = getView().findViewById(R.id.fdIcon); + View v = getView().findViewById(R.id.fdIcon_divider); if (iv != null) { iv.setTag(file.getFileId()); // Name of the file, to deduce the icon to use in case the MIME type is not precise enough - iv.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimetype(), file.getFileName(), mAccount, + iv.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimetype(), file.getFileName(), account, getContext())); - Bitmap thumbnail; + Bitmap resizedImage; if (MimeTypeUtil.isImage(file)) { - String tagId = String.valueOf(file.getRemoteId()); - thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache(tagId); - - if (thumbnail != null && !file.needsUpdateThumbnail()) { - iv.setImageBitmap(thumbnail); + String tagId = String.valueOf(ThumbnailsCacheManager.PREFIX_RESIZED_IMAGE + getFile().getRemoteId()); + resizedImage = ThumbnailsCacheManager.getBitmapFromDiskCache(tagId); + + if (resizedImage != null && !file.needsUpdateThumbnail()) { + iv.setVisibility(View.GONE); + v.setVisibility(View.GONE); + previewImage.setImageBitmap(resizedImage); + activatePreviewImage(); + previewLoaded = true; } else { - // generate new Thumbnail - if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(file, iv)) { - final ThumbnailsCacheManager.ThumbnailGenerationTask task = - new ThumbnailsCacheManager.ThumbnailGenerationTask( - iv, mContainerActivity.getStorageManager(), mAccount - ); - if (thumbnail == null) { - thumbnail = ThumbnailsCacheManager.mDefaultImg; + // show thumbnail while loading resized image + Bitmap thumbnail = ThumbnailsCacheManager.getBitmapFromDiskCache( + String.valueOf(ThumbnailsCacheManager.PREFIX_THUMBNAIL + getFile().getRemoteId())); + + if (thumbnail != null) { + iv.setImageBitmap(thumbnail); + } else { + thumbnail = ThumbnailsCacheManager.mDefaultImg; + } + + // generate new resized image + if (ThumbnailsCacheManager.cancelPotentialThumbnailWork(getFile(), iv) && + mContainerActivity.getStorageManager() != null) { + final ThumbnailsCacheManager.ResizedImageGenerationTask task = + new ThumbnailsCacheManager.ResizedImageGenerationTask(FileDetailFragment.this, + iv, + mContainerActivity.getStorageManager(), + mContainerActivity.getStorageManager().getAccount()); + if (resizedImage == null) { + resizedImage = thumbnail; } - final ThumbnailsCacheManager.AsyncThumbnailDrawable asyncDrawable = - new ThumbnailsCacheManager.AsyncThumbnailDrawable( + final ThumbnailsCacheManager.AsyncResizedImageDrawable asyncDrawable = + new ThumbnailsCacheManager.AsyncResizedImageDrawable( MainApp.getAppContext().getResources(), - thumbnail, + resizedImage, task ); - iv.setImageDrawable(asyncDrawable); - task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, file.getRemoteId())); + iv.setVisibility(View.GONE); + v.setVisibility(View.GONE); + previewImage.setImageDrawable(asyncDrawable); + activatePreviewImage(); + previewLoaded = true; + task.execute(getFile()); } } } else { - iv.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimetype(), file.getFileName(), mAccount, + iv.setImageDrawable(MimeTypeUtil.getFileTypeIcon(file.getMimetype(), file.getFileName(), account, getContext())); } } } + private void makeStatusBarBlack() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + getActivity().getWindow().setStatusBarColor(getResources().getColor(R.color.black)); + } + } + /** * Updates the file size in view * @@ -545,98 +633,11 @@ private void setTimeModified(long milliseconds) { } } - /** - * Updates Share by link data - * - * @param isShareByLink flag is share by link is enable - */ - private void setShareByLinkInfo(boolean isShareByLink) { - TextView tv = getView().findViewById(R.id.fdSharebyLink); - if (tv != null) { - tv.setText(isShareByLink ? R.string.filedetails_share_link_enable : - R.string.filedetails_share_link_disable); - } - ImageView linkIcon = getView().findViewById(R.id.fdShareLinkIcon); - if (linkIcon != null) { - linkIcon.setVisibility(isShareByLink ? View.VISIBLE : View.GONE); - } - } - - /** - * Update Share With data - */ - private void setShareWithUserInfo(){ - // Get Users and Groups - if (((FileActivity) getActivity()).getStorageManager() != null) { - FileDataStorageManager fileDataStorageManager = ((FileActivity) getActivity()).getStorageManager(); - mShares = fileDataStorageManager.getSharesWithForAFile( - getFile().getRemotePath(),mAccount.name - ); - - // Update list of users/groups - updateListOfUserGroups(); - } - } - - private void updateListOfUserGroups() { - // Update list of users/groups - // TODO Refactoring: create a new {@link ShareUserListAdapter} instance with every call should not be needed - UserListAdapter mUserGroupsAdapter = new UserListAdapter( - getActivity().getApplicationContext(), - R.layout.share_user_item, mShares - ); - - // Show data - ListView usersList = getView().findViewById(R.id.fdshareUsersList); - - // No data - TextView noList = getView().findViewById(R.id.fdShareNoUsers); - - if (mShares.size() > 0) { - usersList.setVisibility(View.VISIBLE); - usersList.setAdapter(mUserGroupsAdapter); - noList.setVisibility(View.GONE); - setListViewHeightBasedOnChildren(usersList); - - } else { - usersList.setVisibility(View.GONE); - noList.setVisibility(View.VISIBLE); - } - } - - /** - * Fix scroll in listview when the parent is a ScrollView - */ - private static void setListViewHeightBasedOnChildren(ListView listView) { - ListAdapter listAdapter = listView.getAdapter(); - if (listAdapter == null) { - return; - } - int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.AT_MOST); - int totalHeight = 0; - View view = null; - for (int i = 0; i < listAdapter.getCount(); i++) { - view = listAdapter.getView(i, view, listView); - if (i == 0) { - view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, ViewGroup.LayoutParams.WRAP_CONTENT)); - } - view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED); - totalHeight += view.getMeasuredHeight(); - } - ViewGroup.LayoutParams params = listView.getLayoutParams(); - params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); - listView.setLayoutParams(params); - listView.requestLayout(); - } - /** * Enables or disables buttons for a file being downloaded */ private void setButtonsForTransferring() { if (!isEmpty()) { - // let's protect the user from himself ;) - getView().findViewById(R.id.fdFavorite).setEnabled(false); - // show the progress bar for the transfer getView().findViewById(R.id.fdProgressBlock).setVisibility(View.VISIBLE); TextView progressText = getView().findViewById(R.id.fdProgressText); @@ -644,11 +645,11 @@ private void setButtonsForTransferring() { FileDownloaderBinder downloaderBinder = mContainerActivity.getFileDownloaderBinder(); FileUploaderBinder uploaderBinder = mContainerActivity.getFileUploaderBinder(); //if (getFile().isDownloading()) { - if (downloaderBinder != null && downloaderBinder.isDownloading(mAccount, getFile())) { + if (downloaderBinder != null && downloaderBinder.isDownloading(account, getFile())) { progressText.setText(R.string.downloader_download_in_progress_ticker); } else { - if (uploaderBinder != null && uploaderBinder.isUploading(mAccount, getFile())) { + if (uploaderBinder != null && uploaderBinder.isUploading(account, getFile())) { progressText.setText(R.string.uploader_upload_in_progress_ticker); } } @@ -660,8 +661,6 @@ private void setButtonsForTransferring() { */ private void setButtonsForDown() { if (!isEmpty()) { - getView().findViewById(R.id.fdFavorite).setEnabled(true); - // hides the progress bar getView().findViewById(R.id.fdProgressBlock).setVisibility(View.GONE); TextView progressText = getView().findViewById(R.id.fdProgressText); @@ -674,8 +673,6 @@ private void setButtonsForDown() { */ private void setButtonsForRemote() { if (!isEmpty()) { - getView().findViewById(R.id.fdFavorite).setEnabled(true); - // hides the progress bar getView().findViewById(R.id.fdProgressBlock).setVisibility(View.GONE); TextView progressText = getView().findViewById(R.id.fdProgressText); @@ -683,47 +680,43 @@ private void setButtonsForRemote() { } } - public void listenForTransferProgress() { - if (mProgressListener != null) { + if (progressListener != null) { if (mContainerActivity.getFileDownloaderBinder() != null) { mContainerActivity.getFileDownloaderBinder(). - addDatatransferProgressListener(mProgressListener, mAccount, getFile()); + addDatatransferProgressListener(progressListener, account, getFile()); } if (mContainerActivity.getFileUploaderBinder() != null) { mContainerActivity.getFileUploaderBinder(). - addDatatransferProgressListener(mProgressListener, mAccount, getFile()); + addDatatransferProgressListener(progressListener, account, getFile()); } } else { - Log_OC.d(TAG, "mProgressListener == null"); + Log_OC.d(TAG, "progressListener == null"); } } - public void leaveTransferProgress() { - if (mProgressListener != null) { + if (progressListener != null) { if (mContainerActivity.getFileDownloaderBinder() != null) { mContainerActivity.getFileDownloaderBinder(). - removeDatatransferProgressListener(mProgressListener, mAccount, getFile()); + removeDatatransferProgressListener(progressListener, account, getFile()); } if (mContainerActivity.getFileUploaderBinder() != null) { mContainerActivity.getFileUploaderBinder(). - removeDatatransferProgressListener(mProgressListener, mAccount, getFile()); + removeDatatransferProgressListener(progressListener, account, getFile()); } } } - /** - * Helper class responsible for updating the progress bar shown for file uploading or - * downloading + * Helper class responsible for updating the progress bar shown for file downloading. */ private class ProgressListener implements OnDatatransferProgressListener { - int mLastPercent = 0; - WeakReference mProgressBar = null; + private int mLastPercent = 0; + private WeakReference mProgressBar; ProgressListener(ProgressBar progressBar) { - mProgressBar = new WeakReference(progressBar); + mProgressBar = new WeakReference<>(progressBar); } @Override @@ -739,7 +732,5 @@ public void onTransferProgress(long progressRate, long totalTransferredSoFar, } mLastPercent = percent; } - } - } diff --git a/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java new file mode 100644 index 000000000000..ccecf47cbb27 --- /dev/null +++ b/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java @@ -0,0 +1,177 @@ +/* + * Nextcloud Android client application + * + * @author Andy Scherzinger + * Copyright (C) 2018 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 + * License as published by the Free Software Foundation; either + * version 3 of the License, or 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 . + */ + +package com.owncloud.android.ui.fragment; + +import android.accounts.Account; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import com.owncloud.android.R; +import com.owncloud.android.datamodel.FileDataStorageManager; +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.lib.resources.shares.OCShare; +import com.owncloud.android.ui.activity.FileActivity; +import com.owncloud.android.ui.adapter.UserListAdapter; +import com.owncloud.android.utils.ThemeUtils; + +import java.util.ArrayList; + +public class FileDetailSharingFragment extends Fragment { + + private static final String ARG_FILE = "FILE"; + private static final String ARG_ACCOUNT = "ACCOUNT"; + + // to show share with users/groups info + private ArrayList mShares; + + private OCFile file; + private Account account; + + public static FileDetailSharingFragment newInstance(OCFile file, Account account) { + FileDetailSharingFragment fragment = new FileDetailSharingFragment(); + Bundle args = new Bundle(); + args.putParcelable(ARG_FILE, file); + args.putParcelable(ARG_ACCOUNT, account); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, + Bundle savedInstanceState) { + + file = getArguments().getParcelable(ARG_FILE); + account = getArguments().getParcelable(ARG_ACCOUNT); + + if (savedInstanceState != null) { + file = savedInstanceState.getParcelable(FileActivity.EXTRA_FILE); + account = savedInstanceState.getParcelable(FileActivity.EXTRA_ACCOUNT); + } + + View view = inflater.inflate(R.layout.file_details_sharing_fragment, container, false); + + setupView(view); + + return view; + } + + private void setupView(View view) { + ((TextView)view.findViewById(R.id.fdShareTitle)).setTextColor(ThemeUtils.primaryAccentColor(getContext())); + ((TextView)view.findViewById(R.id.fdShareWithUsersTitle)).setTextColor(ThemeUtils.primaryAccentColor(getContext())); + + setShareByLinkInfo(file.isSharedViaLink(), view); + + setShareWithUserInfo(view); + } + + /** + * Updates Share by link data + * + * @param isShareByLink flag is share by link is enable + */ + private void setShareByLinkInfo(boolean isShareByLink, View view) { + TextView tv = view.findViewById(R.id.fdSharebyLink); + if (tv != null) { + tv.setText(isShareByLink ? R.string.filedetails_share_link_enable : + R.string.filedetails_share_link_disable); + } + ImageView linkIcon = view.findViewById(R.id.fdShareLinkIcon); + if (linkIcon != null) { + linkIcon.setVisibility(isShareByLink ? View.VISIBLE : View.GONE); + } + } + + /** + * Update Share With data + */ + private void setShareWithUserInfo(View view){ + // Get Users and Groups + if (((FileActivity) getActivity()).getStorageManager() != null) { + FileDataStorageManager fileDataStorageManager = ((FileActivity) getActivity()).getStorageManager(); + mShares = fileDataStorageManager.getSharesWithForAFile( + file.getRemotePath(),account.name + ); + + // Update list of users/groups + updateListOfUserGroups(view); + } + } + + private void updateListOfUserGroups(View view) { + // Update list of users/groups + // TODO Refactoring: create a new {@link ShareUserListAdapter} instance with every call should not be needed + UserListAdapter mUserGroupsAdapter = new UserListAdapter( + getActivity().getApplicationContext(), + R.layout.share_user_item, mShares + ); + + // Show data + ListView usersList = view.findViewById(R.id.fdshareUsersList); + + // No data + TextView noList = view.findViewById(R.id.fdShareNoUsers); + + if (mShares.size() > 0) { + usersList.setVisibility(View.VISIBLE); + usersList.setAdapter(mUserGroupsAdapter); + noList.setVisibility(View.GONE); + setListViewHeightBasedOnChildren(usersList); + + } else { + usersList.setVisibility(View.GONE); + noList.setVisibility(View.VISIBLE); + } + } + + /** + * Fix scroll in listview when the parent is a ScrollView + */ + private static void setListViewHeightBasedOnChildren(ListView listView) { + ListAdapter listAdapter = listView.getAdapter(); + if (listAdapter == null) { + return; + } + int desiredWidth = View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.AT_MOST); + int totalHeight = 0; + View view = null; + for (int i = 0; i < listAdapter.getCount(); i++) { + view = listAdapter.getView(i, view, listView); + if (i == 0) { + view.setLayoutParams(new ViewGroup.LayoutParams(desiredWidth, ViewGroup.LayoutParams.WRAP_CONTENT)); + } + view.measure(desiredWidth, View.MeasureSpec.UNSPECIFIED); + totalHeight += view.getMeasuredHeight(); + } + ViewGroup.LayoutParams params = listView.getLayoutParams(); + params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); + listView.setLayoutParams(params); + listView.requestLayout(); + } +} diff --git a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java index 5d7e0a5bad03..0ba7ae18d8c2 100755 --- a/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java +++ b/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java @@ -728,7 +728,7 @@ public void toggleFavoriteFiles(Collection files, boolean shouldBeFavori } } - private void toggleFavoriteFile(OCFile file, boolean shouldBeFavorite) { + public void toggleFavoriteFile(OCFile file, boolean shouldBeFavorite) { if (file.getIsFavorite() != shouldBeFavorite) { EventBus.getDefault().post(new FavoriteEvent(file.getRemotePath(), shouldBeFavorite, file.getRemoteId())); } diff --git a/src/main/res/drawable/ic_star.xml b/src/main/res/drawable/ic_star.xml new file mode 100644 index 000000000000..62098dfa298b --- /dev/null +++ b/src/main/res/drawable/ic_star.xml @@ -0,0 +1,23 @@ + + + + diff --git a/src/main/res/drawable/ic_star_outline.xml b/src/main/res/drawable/ic_star_outline.xml new file mode 100644 index 000000000000..4920bfe44120 --- /dev/null +++ b/src/main/res/drawable/ic_star_outline.xml @@ -0,0 +1,23 @@ + + + + diff --git a/src/main/res/drawable/ic_tag.xml b/src/main/res/drawable/ic_tag.xml new file mode 100644 index 000000000000..83b704123a6a --- /dev/null +++ b/src/main/res/drawable/ic_tag.xml @@ -0,0 +1,23 @@ + + + + diff --git a/src/main/res/layout/file_details_activities_fragment.xml b/src/main/res/layout/file_details_activities_fragment.xml new file mode 100644 index 000000000000..ca619eecbf38 --- /dev/null +++ b/src/main/res/layout/file_details_activities_fragment.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + diff --git a/src/main/res/layout/file_details_fragment.xml b/src/main/res/layout/file_details_fragment.xml index 6d191433ade0..9804d97e26e7 100644 --- a/src/main/res/layout/file_details_fragment.xml +++ b/src/main/res/layout/file_details_fragment.xml @@ -18,7 +18,7 @@ along with this program. If not, see . --> - + android:layout_margin="@dimen/standard_margin" + android:contentDescription="@string/file_icon" + android:src="@drawable/file" /> - + + + + android:textColor="@color/black" + android:textSize="16sp" /> + + + android:textSize="16sp" /> + android:textSize="@dimen/two_line_secondary_text_size" /> - - - - - - - - - - - - - - - - + android:textSize="16sp" /> - - - + android:layout_marginEnd="@dimen/standard_eighth_margin" + android:layout_marginLeft="@dimen/standard_margin" + android:layout_marginRight="@dimen/standard_eighth_margin" + android:layout_marginStart="@dimen/standard_margin" + android:contentDescription="@null" + android:src="@drawable/ic_tag" + android:visibility="gone" /> - + android:text="@string/tags" + android:visibility="gone" /> - - - + + + android:text="@string/downloader_download_in_progress_ticker" /> - - + android:layout_marginBottom="@dimen/standard_quarter_margin" + android:gravity="center" + android:orientation="horizontal"> + + - + android:layout_marginLeft="@dimen/standard_half_margin" + android:layout_marginStart="@dimen/standard_half_margin" + android:background="@android:color/transparent" + android:contentDescription="@string/common_cancel" + android:src="@drawable/ic_cancel" /> + - - - + - + - + + + diff --git a/src/main/res/layout/file_details_share_user_item.xml b/src/main/res/layout/file_details_share_user_item.xml index 159f936d35ad..616c432dba60 100644 --- a/src/main/res/layout/file_details_share_user_item.xml +++ b/src/main/res/layout/file_details_share_user_item.xml @@ -21,6 +21,8 @@ android:layout_height="wrap_content" android:orientation="horizontal" android:weightSum="1" + android:paddingTop="@dimen/standard_eigth_padding" + android:paddingBottom="@dimen/standard_eigth_padding" tools:ignore="UseCompoundDrawables"> diff --git a/src/main/res/layout/file_details_sharing_fragment.xml b/src/main/res/layout/file_details_sharing_fragment.xml new file mode 100644 index 000000000000..ace16c377294 --- /dev/null +++ b/src/main/res/layout/file_details_sharing_fragment.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/res/layout/log_send_file.xml b/src/main/res/layout/log_send_file.xml index 2713ff7d6c7f..12c66558207d 100644 --- a/src/main/res/layout/log_send_file.xml +++ b/src/main/res/layout/log_send_file.xml @@ -28,7 +28,7 @@ diff --git a/src/main/res/layout/share_user_item.xml b/src/main/res/layout/share_user_item.xml index ed78057db2e0..b111ab02d039 100644 --- a/src/main/res/layout/share_user_item.xml +++ b/src/main/res/layout/share_user_item.xml @@ -27,8 +27,8 @@ android:weightSum="1" android:longClickable="true"> + android:gravity="center_vertical"/> . --> - - - - - - \ No newline at end of file + android:layout_height="wrap_content"> + + + + + + + + + diff --git a/src/main/res/values/dims.xml b/src/main/res/values/dims.xml index fb1cebc19e7b..f2700b298106 100644 --- a/src/main/res/values/dims.xml +++ b/src/main/res/values/dims.xml @@ -107,7 +107,6 @@ 32dp 32dp 16sp - 12dp 24dp 16dp 16dp diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 5dfffd02f699..7fc009dd1b5e 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -269,7 +269,6 @@ Unset as available offline Set as favorite Unset favorite - Available offline Set as encrypted Unset encryption Rename @@ -784,4 +783,5 @@ Upload content from other apps Create new folder Virus detected. Upload cannot be completed! + Tags