Merge pull request #9112 from nextcloud/profilePage

Profile page
This commit is contained in:
Tobias Kaminsky 2021-10-25 15:07:32 +02:00 коммит произвёл GitHub
Родитель 765e2ca442 6d07584a54
Коммит d544e18960
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 503 добавлений и 28 удалений

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 13 KiB

Просмотреть файл

@ -31,6 +31,8 @@ import android.view.ViewGroup;
import android.widget.TextView;
import com.google.gson.Gson;
import com.nextcloud.android.lib.resources.profile.Action;
import com.nextcloud.android.lib.resources.profile.HoverCard;
import com.nextcloud.client.account.RegisteredUser;
import com.nextcloud.client.account.Server;
import com.nextcloud.client.device.DeviceInfo;
@ -54,6 +56,7 @@ import com.owncloud.android.lib.resources.users.StatusType;
import com.owncloud.android.ui.activity.FileDisplayActivity;
import com.owncloud.android.ui.fragment.OCFileListBottomSheetActions;
import com.owncloud.android.ui.fragment.OCFileListBottomSheetDialog;
import com.owncloud.android.ui.fragment.ProfileBottomSheetDialog;
import com.owncloud.android.utils.MimeTypeUtil;
import com.owncloud.android.utils.ScreenshotTest;
@ -64,6 +67,7 @@ import org.junit.Test;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import androidx.fragment.app.DialogFragment;
@ -378,6 +382,47 @@ public class DialogFragmentIT extends AbstractIT {
screenshot(sut.getWindow().getDecorView());
}
@Test
@ScreenshotTest
public void testProfileBottomSheet() {
if (Looper.myLooper() == null) {
Looper.prepare();
}
// Fixed values for HoverCard
List<Action> actions = new ArrayList<>();
actions.add(new Action("profile",
"View profile",
"https://dev.nextcloud.com/core/img/actions/profile.svg",
"https://dev.nextcloud.com/index.php/u/christine"));
actions.add(new Action("core",
"christine.scott@nextcloud.com",
"https://dev.nextcloud.com/core/img/actions/mail.svg",
"mailto:christine.scott@nextcloud.com"));
actions.add(new Action("spreed",
"Talk to Christine",
"https://dev.nextcloud.com/apps/spreed/img/app-dark.svg",
"https://dev.nextcloud.com/apps/spreed/?callUser=christine"
));
HoverCard hoverCard = new HoverCard("christine", "Christine Scott", actions);
// show dialog
Intent intent = new Intent(targetContext, FileDisplayActivity.class);
FileDisplayActivity fda = activityRule.launchActivity(intent);
ProfileBottomSheetDialog sut = new ProfileBottomSheetDialog(fda,
user,
hoverCard);
fda.runOnUiThread(sut::show);
waitForIdleSync();
screenshot(sut.getWindow().getDecorView());
}
private FileDisplayActivity showDialog(DialogFragment dialog) {
Intent intent = new Intent(targetContext, FileDisplayActivity.class);
FileDisplayActivity sut = activityRule.launchActivity(intent);

Просмотреть файл

@ -869,6 +869,7 @@ public final class ThumbnailsCacheManager {
private final float mAvatarRadius;
private User user;
private String mUserId;
private String displayName;
private String mServerName;
private Context mContext;
@ -879,6 +880,7 @@ public final class ThumbnailsCacheManager {
Resources resources,
float avatarRadius,
String userId,
String displayName,
String serverName,
Context context) {
mAvatarGenerationListener = new WeakReference<>(avatarGenerationListener);
@ -887,6 +889,7 @@ public final class ThumbnailsCacheManager {
mResources = resources;
mAvatarRadius = avatarRadius;
mUserId = userId;
this.displayName = displayName;
mServerName = serverName;
mContext = context;
}
@ -1023,7 +1026,7 @@ public final class ThumbnailsCacheManager {
if (avatar == null) {
try {
return TextDrawable.createAvatar(user, mAvatarRadius);
return TextDrawable.createAvatarByUserId(displayName, mAvatarRadius);
} catch (Exception e1) {
return ResourcesCompat.getDrawable(mResources, R.drawable.ic_user, null);
}

Просмотреть файл

@ -48,7 +48,9 @@ class ShareViewHolder extends RecyclerView.ViewHolder {
super(itemView);
}
public ShareViewHolder(FileDetailsShareShareItemBinding binding, User user, Context context) {
public ShareViewHolder(FileDetailsShareShareItemBinding binding,
User user,
Context context) {
this(binding.getRoot());
this.binding = binding;
this.user = user;
@ -91,6 +93,8 @@ class ShareViewHolder extends RecyclerView.ViewHolder {
context.getResources(),
binding.icon,
context);
binding.icon.setOnClickListener(v -> listener.showProfileBottomSheet(user, share.getShareWith()));
default:
setImage(binding.icon, name, R.drawable.ic_user);
break;

Просмотреть файл

@ -25,7 +25,6 @@
package com.owncloud.android.ui.adapter;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@ -39,6 +38,7 @@ import com.owncloud.android.databinding.FileDetailsSharePublicLinkAddNewItemBind
import com.owncloud.android.databinding.FileDetailsShareShareItemBinding;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.utils.DisplayUtils;
import java.util.ArrayList;
@ -55,24 +55,24 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
implements DisplayUtils.AvatarGenerationListener {
private ShareeListAdapterListener listener;
private Context context;
private FileActivity fileActivity;
private List<OCShare> shares;
private float avatarRadiusDimension;
private String userId;
private User user;
public ShareeListAdapter(Context context,
public ShareeListAdapter(FileActivity fileActivity,
List<OCShare> shares,
ShareeListAdapterListener listener,
String userId,
User user) {
this.context = context;
this.fileActivity = fileActivity;
this.shares = shares;
this.listener = listener;
this.userId = userId;
this.user = user;
avatarRadiusDimension = context.getResources().getDimension(R.dimen.user_icon_radius);
avatarRadiusDimension = fileActivity.getResources().getDimension(R.dimen.user_icon_radius);
sortShares();
}
@ -89,26 +89,26 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
case PUBLIC_LINK:
case EMAIL:
return new LinkShareViewHolder(
FileDetailsShareLinkShareItemBinding.inflate(LayoutInflater.from(context),
FileDetailsShareLinkShareItemBinding.inflate(LayoutInflater.from(fileActivity),
parent,
false),
context);
fileActivity);
case NEW_PUBLIC_LINK:
return new NewLinkShareViewHolder(
FileDetailsSharePublicLinkAddNewItemBinding.inflate(LayoutInflater.from(context),
FileDetailsSharePublicLinkAddNewItemBinding.inflate(LayoutInflater.from(fileActivity),
parent,
false)
);
case INTERNAL:
return new InternalShareViewHolder(
FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(context), parent, false),
context);
FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false),
fileActivity);
default:
return new ShareViewHolder(FileDetailsShareShareItemBinding.inflate(LayoutInflater.from(context),
return new ShareViewHolder(FileDetailsShareShareItemBinding.inflate(LayoutInflater.from(fileActivity),
parent,
false),
user,
context);
fileActivity);
}
}

Просмотреть файл

@ -24,6 +24,7 @@ package com.owncloud.android.ui.adapter;
import android.widget.ImageView;
import com.nextcloud.client.account.User;
import com.owncloud.android.lib.resources.shares.OCShare;
public interface ShareeListAdapterListener {
@ -38,4 +39,6 @@ public interface ShareeListAdapterListener {
void createPublicShareLink();
void requestPasswordForShare(OCShare share, boolean askForPassword);
void showProfileBottomSheet(User user, String shareWith);
}

Просмотреть файл

@ -0,0 +1,85 @@
/*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2021 Tobias Kaminsky
* Copyright (C) 2021 Nextcloud GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.asynctasks;
import android.os.AsyncTask;
import com.nextcloud.android.lib.resources.profile.GetHoverCardRemoteOperation;
import com.nextcloud.android.lib.resources.profile.HoverCard;
import com.nextcloud.client.account.User;
import com.nextcloud.client.network.ClientFactory;
import com.nextcloud.common.NextcloudClient;
import com.owncloud.android.R;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.ui.fragment.ProfileBottomSheetDialog;
import com.owncloud.android.utils.DisplayUtils;
import java.lang.ref.WeakReference;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.Lifecycle;
public class RetrieveHoverCardAsyncTask extends AsyncTask<Void, Void, HoverCard> {
private final User user;
private final String userId;
private final WeakReference<FragmentActivity> activityWeakReference;
private final ClientFactory clientFactory;
public RetrieveHoverCardAsyncTask(User user,
String userId,
FragmentActivity activity,
ClientFactory clientFactory) {
this.user = user;
this.userId = userId;
this.activityWeakReference = new WeakReference<>(activity);
this.clientFactory = clientFactory;
}
@Override
protected HoverCard doInBackground(Void... voids) {
try {
NextcloudClient client = clientFactory.createNextcloudClient(user);
RemoteOperationResult<HoverCard> result = new GetHoverCardRemoteOperation(userId).execute(client);
if (result.isSuccess()) {
return result.getResultData();
} else {
return null;
}
} catch (ClientFactory.CreationException | NullPointerException e) {
return null;
}
}
@Override
protected void onPostExecute(HoverCard hoverCard) {
FragmentActivity activity = this.activityWeakReference.get();
if (activity != null && activity.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
if (hoverCard.getActions().size() > 0) {
new ProfileBottomSheetDialog(activity, user, hoverCard).show();
} else {
DisplayUtils.showSnackMessage(activity, R.string.no_actions);
}
}
}
}

Просмотреть файл

@ -41,6 +41,7 @@ import android.widget.ImageView;
import com.nextcloud.client.account.User;
import com.nextcloud.client.account.UserAccountManager;
import com.nextcloud.client.di.Injectable;
import com.nextcloud.client.network.ClientFactory;
import com.owncloud.android.R;
import com.owncloud.android.databinding.FileDetailsSharingFragmentBinding;
import com.owncloud.android.datamodel.FileDataStorageManager;
@ -50,12 +51,14 @@ import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.resources.shares.OCShare;
import com.owncloud.android.lib.resources.shares.SharePermissionsBuilder;
import com.owncloud.android.lib.resources.shares.ShareType;
import com.owncloud.android.lib.resources.status.NextcloudVersion;
import com.owncloud.android.lib.resources.status.OCCapability;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.activity.FileDisplayActivity;
import com.owncloud.android.ui.adapter.ShareeListAdapter;
import com.owncloud.android.ui.adapter.ShareeListAdapterListener;
import com.owncloud.android.ui.asynctasks.RetrieveHoverCardAsyncTask;
import com.owncloud.android.ui.dialog.ExpirationDatePickerDialogFragment;
import com.owncloud.android.ui.dialog.NoteDialogFragment;
import com.owncloud.android.ui.dialog.RenamePublicShareDialogFragment;
@ -110,6 +113,8 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
@Inject UserAccountManager accountManager;
@Inject ClientFactory clientFactory;
public static FileDetailSharingFragment newInstance(OCFile file, User user) {
FileDetailSharingFragment fragment = new FileDetailSharingFragment();
Bundle args = new Bundle();
@ -607,6 +612,13 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
dialog.show(getChildFragmentManager(), SharePasswordDialogFragment.PASSWORD_FRAGMENT);
}
@Override
public void showProfileBottomSheet(User user, String shareWith) {
if (user.getServer().getVersion().isNewerOrEqual(NextcloudVersion.Companion.getNextcloud_23())) {
new RetrieveHoverCardAsyncTask(user, shareWith, fileActivity, clientFactory).execute();
}
}
/**
* Get known server capabilities from DB
*/

Просмотреть файл

@ -0,0 +1,176 @@
/*
* Nextcloud Android client application
*
* @author Tobias Kaminsky
* Copyright (C) 2021 Tobias Kaminsky
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owncloud.android.ui.fragment
import android.content.ActivityNotFoundException
import android.content.DialogInterface
import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.FragmentActivity
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.nextcloud.android.lib.resources.profile.Action
import com.nextcloud.android.lib.resources.profile.HoverCard
import com.nextcloud.client.account.User
import com.owncloud.android.R
import com.owncloud.android.databinding.ProfileBottomSheetActionBinding
import com.owncloud.android.databinding.ProfileBottomSheetFragmentBinding
import com.owncloud.android.utils.DisplayUtils
import com.owncloud.android.utils.theme.ThemeColorUtils
import com.owncloud.android.utils.theme.ThemeDrawableUtils
/**
* Show actions of an user
*/
class ProfileBottomSheetDialog(
private val fileActivity: FragmentActivity,
private val user: User,
private val hoverCard: HoverCard
) : BottomSheetDialog(fileActivity), DisplayUtils.AvatarGenerationListener {
private var _binding: ProfileBottomSheetFragmentBinding? = null
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ProfileBottomSheetFragmentBinding.inflate(layoutInflater)
setContentView(binding.root)
if (window != null) {
window!!.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
val primaryColor = ThemeColorUtils.primaryColor(context, true)
binding.icon.tag = hoverCard.userId
DisplayUtils.setAvatar(
user,
hoverCard.userId,
hoverCard.displayName,
this,
context.resources.getDimension(R.dimen.list_item_avatar_icon_radius),
context.resources,
binding.icon,
context
)
binding.displayName.text = hoverCard.displayName
for (action in hoverCard.actions) {
val actionBinding = ProfileBottomSheetActionBinding.inflate(
layoutInflater
)
val creatorView: View = actionBinding.root
if (action.appId == "email") {
action.hyperlink = action.title
action.title = context.resources.getString(R.string.write_email)
}
actionBinding.name.text = action.title
val icon = when (action.appId) {
"profile" -> R.drawable.ic_user
"email" -> R.drawable.ic_email
"spreed" -> R.drawable.ic_talk
else -> R.drawable.ic_edit
}
actionBinding.icon.setImageDrawable(
ResourcesCompat.getDrawable(
context.resources,
icon,
null
)
)
ThemeDrawableUtils.tintDrawable(actionBinding.icon.drawable, primaryColor)
creatorView.setOnClickListener { v: View? ->
send(hoverCard.userId, action)
dismiss()
}
binding.creators.addView(creatorView)
}
setOnShowListener { d: DialogInterface? ->
BottomSheetBehavior.from(binding.root.parent as View)
.setPeekHeight(binding.root.measuredHeight)
}
}
private fun send(userId: String, action: Action) {
when (action.appId) {
"profile" -> openWebsite(action.hyperlink)
"core" -> sendEmail(action.hyperlink)
"spreed" -> openTalk(userId, action.hyperlink)
}
}
private fun openWebsite(url: String) {
DisplayUtils.startLinkIntent(fileActivity, url)
}
private fun sendEmail(email: String) {
val intent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:")
putExtra(Intent.EXTRA_EMAIL, arrayOf(email))
}
DisplayUtils.startIntentIfAppAvailable(intent, fileActivity, R.string.no_email_app_available)
}
private fun openTalk(userId: String, hyperlink: String) {
try {
val sharingIntent = Intent(Intent.ACTION_VIEW)
sharingIntent.setClassName(
"com.nextcloud.talk2",
"com.nextcloud.talk.activities.MainActivity"
)
sharingIntent.putExtra("server", user.server.uri)
sharingIntent.putExtra("userId", userId)
fileActivity.startActivity(sharingIntent)
} catch (e: ActivityNotFoundException) {
openWebsite(hyperlink)
}
}
override fun onStop() {
super.onStop()
_binding = null
}
override fun avatarGenerated(avatarDrawable: Drawable?, callContext: Any?) {
if (callContext is ImageView) {
callContext.setImageDrawable(avatarDrawable)
}
}
override fun shouldCallGeneratedCallback(tag: String?, callContext: Any?): Boolean {
if (callContext is ImageView) {
// needs to be changed once federated users have avatars
return callContext.tag.toString() == tag!!.split("@").toTypedArray()[0]
}
return false
}
}

Просмотреть файл

@ -527,6 +527,7 @@ public final class DisplayUtils {
resources,
avatarRadius,
userId,
displayName,
serverName,
context);
@ -755,10 +756,18 @@ public final class DisplayUtils {
}
static public void startLinkIntent(Activity activity, @StringRes int link) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(activity.getString(link)));
startLinkIntent(activity, activity.getString(link));
}
static public void startLinkIntent(Activity activity, Uri url) {
Intent intent = new Intent(Intent.ACTION_VIEW, url);
DisplayUtils.startIntentIfAppAvailable(intent, activity, R.string.no_browser_available);
}
static public void startLinkIntent(Activity activity, String url) {
startLinkIntent(activity, Uri.parse(url));
}
static public void startIntentIfAppAvailable(Intent intent, Activity activity, @StringRes int error) {
if (intent.resolveActivity(activity.getPackageManager()) != null) {
activity.startActivity(intent);

Просмотреть файл

@ -2,7 +2,7 @@
<!--
Nextcloud Android client application
Copyright (C) 2020 Nextcloud GmbH
Copyright (C) 2021 Nextcloud GmbH
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
@ -17,13 +17,14 @@
You should have received a copy of the GNU Affero General Public
License along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="128"
android:viewportHeight="128">
<vector android:autoMirrored="true"
android:height="16dp"
android:viewportHeight="16"
android:viewportWidth="16"
android:width="16dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#757575"
android:pathData="M63.992,0.689C29.031,0.689 0.691,29.031 0.692,63.992c0,34.96 28.34,63.301 63.3,63.302 6.982,-0.014 13.881,-1.183 20.426,-3.43 4.317,-1.482 8.48,-3.433 12.411,-5.831 3.383,1.344 8.59,3.838 13.736,5.902 6.688,2.683 13.274,4.639 15.618,2.399 2.317,-2.212 0.703,-8.809 -1.647,-15.575 -2.046,-5.892 -4.649,-11.913 -5.701,-15.282 2.544,-4.415 4.535,-9.101 5.945,-13.954 1.648,-5.674 2.5,-11.574 2.512,-17.532C127.291,29.032 98.952,0.692 63.992,0.691ZM63.999,24.756l0.001,0c21.677,0 39.25,17.573 39.25,39.251 -0.001,21.677 -17.574,39.249 -39.251,39.249 -21.676,0 -39.249,-17.572 -39.25,-39.249 0,-21.678 17.573,-39.251 39.25,-39.251z"
android:strokeWidth="4.78543139" />
android:fillColor="#FF000000"
android:pathData="m7.9992,0.999a6.9993,6.9994 0,0 0,-6.9992 6.9996,6.9993 6.9994,0 0,0 6.9992,6.9994 6.9993,6.9994 0,0 0,3.6308 -1.024c0.8602,0.3418 2.7871,1.356 3.2457,0.9179 0.4792,-0.4577 -0.5626,-2.6116 -0.8124,-3.412a6.9993,6.9994 0,0 0,0.935 -3.4814,6.9993 6.9994,0 0,0 -6.9991,-6.9993zM8,3.6601a4.34,4.3401 0,0 1,4.34 4.3401,4.34 4.3401,0 0,1 -4.34,4.3398 4.34,4.3401 0,0 1,-4.34 -4.3398,4.34 4.3401,0 0,1 4.34,-4.3401z"
android:strokeWidth=".14" />
</vector>

Просмотреть файл

@ -21,8 +21,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:background="@color/bg_default">
android:orientation="vertical">
<TextView
android:id="@+id/add_to_cloud"
@ -31,7 +30,7 @@
android:padding="@dimen/standard_padding"
android:text="@string/add_to_cloud"
android:textSize="@dimen/bottom_sheet_text_size"
android:textColor="@color/text_color"/>
android:textColor="@color/text_color" />
<LinearLayout
android:id="@+id/menu_upload_files"

Просмотреть файл

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?><!--
~
~ Nextcloud Android client application
~
~ @author Tobias Kaminsky
~ Copyright (C) 2019 Tobias Kaminsky
~ Copyright (C) 2019 Nextcloud GmbH
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU Affero General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU Affero General Public License for more details.
~
~ You should have received a copy of the GNU Affero General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="24dp"
android:paddingTop="@dimen/standard_half_padding"
android:paddingEnd="@dimen/standard_padding"
android:paddingBottom="@dimen/standard_half_padding"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@null"
tools:src="@drawable/ic_email" />
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingStart="24dp"
android:paddingEnd="0dp"
tools:text="Compose email"
android:textColor="@color/text_color"
android:textSize="@dimen/bottom_sheet_text_size" />
</LinearLayout>

Просмотреть файл

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8"?><!--
Nextcloud Android client application
Copyright (C) 2021 Tobias Kaminsky
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 <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/icon"
android:layout_width="@dimen/user_icon_size"
android:layout_height="@dimen/user_icon_size"
android:layout_gravity="center_vertical"
android:layout_marginBottom="@dimen/standard_half_margin"
android:layout_marginEnd="@dimen/standard_margin"
android:layout_marginLeft="@dimen/standard_margin"
android:layout_marginRight="@dimen/standard_margin"
android:layout_marginStart="@dimen/standard_margin"
android:layout_marginTop="@dimen/standard_half_margin"
android:contentDescription="@string/user_icon"
android:src="@drawable/ic_user" />
<TextView
android:id="@+id/displayName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingTop="@dimen/standard_padding"
android:paddingBottom="@dimen/standard_padding"
tools:text="Christine Scott"
android:textColor="@color/text_color"
android:textSize="@dimen/bottom_sheet_text_size" />
</LinearLayout>
<LinearLayout
android:id="@+id/action_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="visible"
tools:visibility="visible">
<LinearLayout
android:id="@+id/creators"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"></LinearLayout>
</LinearLayout>
</LinearLayout>

Просмотреть файл

@ -781,6 +781,7 @@
<string name="hint_note">Note</string>
<string name="no_browser_available">No app available to handle links</string>
<string name="no_pdf_app_available">No App available to handle PDF</string>
<string name="no_email_app_available">No App available to handle mail address</string>
<string name="share_via_link_hide_download">Hide download</string>
<string name="unread_comments">Unread comments exist</string>
<string name="richdocuments_failed_to_load_document">Failed to load document!</string>
@ -962,4 +963,6 @@
<string name="strict_mode">Strict mode: no HTTP connection allowed!</string>
<string name="fullscreen">Fullscreen</string>
<string name="more">More</string>
<string name="write_email">Send email</string>
<string name="no_actions">No actions for this user</string>
</resources>

Просмотреть файл

@ -26,6 +26,7 @@ import android.content.res.Resources
import com.nextcloud.client.account.AnonymousUser
import com.owncloud.android.lib.resources.shares.OCShare
import com.owncloud.android.lib.resources.shares.ShareType
import com.owncloud.android.ui.activity.FileActivity
import org.junit.Assert
import org.junit.Test
import org.mockito.Mock
@ -37,11 +38,15 @@ class ShareeListAdapterTest {
@Mock
private val context: Context? = null
@Mock
private val fileActivity: FileActivity? = null
@Test
fun testSorting() {
MockitoAnnotations.openMocks(this)
val resources = Mockito.mock(Resources::class.java)
Mockito.`when`(context!!.resources).thenReturn(resources)
Mockito.`when`(fileActivity!!.resources).thenReturn(resources)
val expectedSortOrder: MutableList<OCShare?> = ArrayList()
expectedSortOrder.add(
OCShare("/1").apply {
@ -83,7 +88,13 @@ class ShareeListAdapterTest {
val randomOrder: MutableList<OCShare?> = ArrayList(expectedSortOrder)
randomOrder.shuffle()
val user = AnonymousUser("nextcloud")
val sut = ShareeListAdapter(context, randomOrder, null, null, user)
val sut = ShareeListAdapter(
fileActivity,
randomOrder,
null,
user.accountName,
user
)
sut.sortShares()
// compare