Skip to content

Commit 7ca2a0b

Browse files
committed
Customizations done for Sharing with test cases.
1 parent 0260bdc commit 7ca2a0b

File tree

64 files changed

+2745
-799
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2745
-799
lines changed

app/src/androidTest/java/com/nmc/android/ui/FileSharingIT.kt

Lines changed: 392 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package com.nmc.android.ui
2+
3+
import android.content.res.Resources
4+
import android.view.View
5+
import androidx.recyclerview.widget.RecyclerView
6+
import androidx.test.espresso.UiController
7+
import androidx.test.espresso.ViewAction
8+
import org.hamcrest.Description
9+
import org.hamcrest.Matcher
10+
import org.hamcrest.TypeSafeMatcher
11+
12+
object RecyclerViewAssertions {
13+
14+
fun clickChildViewWithId(id: Int): ViewAction {
15+
return object : ViewAction {
16+
override fun getConstraints(): Matcher<View>? {
17+
return null
18+
}
19+
20+
override fun getDescription(): String {
21+
return "Click on a child view with specified id."
22+
}
23+
24+
override fun perform(uiController: UiController?, view: View) {
25+
val v: View = view.findViewById(id)
26+
v.performClick()
27+
}
28+
}
29+
}
30+
31+
fun withRecyclerView(recyclerViewId: Int): RecyclerViewMatcher {
32+
return RecyclerViewMatcher(recyclerViewId)
33+
}
34+
35+
class RecyclerViewMatcher(private val recyclerViewId: Int) {
36+
fun atPosition(position: Int): Matcher<View> {
37+
return atPositionOnView(position, -1)
38+
}
39+
40+
fun atPositionOnView(position: Int, targetViewId: Int): Matcher<View> {
41+
return object : TypeSafeMatcher<View>() {
42+
var resources: Resources? = null
43+
var childView: View? = null
44+
45+
override fun describeTo(description: Description?) {
46+
var idDescription = recyclerViewId.toString()
47+
resources?.let {
48+
idDescription = try {
49+
resources!!.getResourceName(recyclerViewId)
50+
} catch (exception: Resources.NotFoundException) {
51+
"$recyclerViewId (resource name not found)"
52+
}
53+
}
54+
55+
description?.appendText("with id: $idDescription")
56+
}
57+
58+
override fun matchesSafely(view: View?): Boolean {
59+
resources = view?.resources
60+
61+
if (childView == null) {
62+
val recyclerView = view?.rootView?.findViewById<RecyclerView>(recyclerViewId)
63+
64+
if (recyclerView != null && recyclerView.id == recyclerViewId) {
65+
childView = recyclerView.findViewHolderForAdapterPosition(position)?.itemView
66+
} else {
67+
return false
68+
}
69+
}
70+
71+
return if (targetViewId == -1) {
72+
view == childView
73+
} else {
74+
val targetView = childView?.findViewById<View>(targetViewId)
75+
view == targetView
76+
}
77+
}
78+
}
79+
}
80+
}
81+
}

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,8 @@
451451
android:label="@string/share_dialog_title"
452452
android:launchMode="singleTop"
453453
android:theme="@style/Theme.ownCloud.Dialog.NoTitle"
454-
android:windowSoftInputMode="adjustResize">
454+
android:configChanges="orientation|screenSize"
455+
android:windowSoftInputMode="adjustPan">
455456
<intent-filter>
456457
<action android:name="android.intent.action.SEARCH" />
457458
</intent-filter>
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package com.nmc.android.utils
2+
3+
import android.content.res.ColorStateList
4+
import androidx.appcompat.widget.AppCompatCheckBox
5+
import androidx.appcompat.widget.SwitchCompat
6+
import androidx.core.graphics.drawable.DrawableCompat
7+
import androidx.core.widget.CompoundButtonCompat
8+
import com.owncloud.android.MainApp
9+
import com.owncloud.android.R
10+
11+
object CheckableThemeUtils {
12+
@JvmStatic
13+
fun tintCheckbox(vararg checkBoxes: AppCompatCheckBox) {
14+
for (checkBox in checkBoxes) {
15+
val checkEnabled = MainApp.getAppContext().resources.getColor(R.color.checkbox_checked_enabled)
16+
val checkDisabled = MainApp.getAppContext().resources.getColor(R.color.checkbox_checked_disabled)
17+
val uncheckEnabled = MainApp.getAppContext().resources.getColor(R.color.checkbox_unchecked_enabled)
18+
val uncheckDisabled = MainApp.getAppContext().resources.getColor(R.color.checkbox_unchecked_disabled)
19+
20+
val states = arrayOf(
21+
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked),
22+
intArrayOf(-android.R.attr.state_enabled, android.R.attr.state_checked),
23+
intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked),
24+
intArrayOf(-android.R.attr.state_enabled, -android.R.attr.state_checked)
25+
)
26+
val colors = intArrayOf(
27+
checkEnabled,
28+
checkDisabled,
29+
uncheckEnabled,
30+
uncheckDisabled
31+
)
32+
val checkColorStateList = ColorStateList(states, colors)
33+
CompoundButtonCompat.setButtonTintList(checkBox, checkColorStateList)
34+
}
35+
}
36+
37+
@JvmStatic
38+
@JvmOverloads
39+
fun tintSwitch(switchView: SwitchCompat, color: Int = 0, colorText: Boolean = false) {
40+
if (colorText) {
41+
switchView.setTextColor(color)
42+
}
43+
val thumbColorCheckedEnabled = MainApp.getAppContext().resources.getColor(R.color.switch_thumb_checked_enabled)
44+
val thumbColorUncheckedEnabled =
45+
MainApp.getAppContext().resources.getColor(R.color.switch_thumb_unchecked_enabled)
46+
val thumbColorCheckedDisabled =
47+
MainApp.getAppContext().resources.getColor(R.color.switch_thumb_checked_disabled)
48+
val thumbColorUncheckedDisabled =
49+
MainApp.getAppContext().resources.getColor(R.color.switch_thumb_unchecked_disabled)
50+
51+
val states = arrayOf(
52+
intArrayOf(android.R.attr.state_enabled, android.R.attr.state_checked),
53+
intArrayOf(-android.R.attr.state_enabled, android.R.attr.state_checked),
54+
intArrayOf(android.R.attr.state_enabled, -android.R.attr.state_checked),
55+
intArrayOf(-android.R.attr.state_enabled, -android.R.attr.state_checked)
56+
)
57+
val thumbColors = intArrayOf(
58+
thumbColorCheckedEnabled,
59+
thumbColorCheckedDisabled,
60+
thumbColorUncheckedEnabled,
61+
thumbColorUncheckedDisabled
62+
)
63+
val thumbColorStateList = ColorStateList(states, thumbColors)
64+
val trackColorCheckedEnabled = MainApp.getAppContext().resources.getColor(R.color.switch_track_checked_enabled)
65+
val trackColorUncheckedEnabled =
66+
MainApp.getAppContext().resources.getColor(R.color.switch_track_unchecked_enabled)
67+
val trackColorCheckedDisabled =
68+
MainApp.getAppContext().resources.getColor(R.color.switch_track_checked_disabled)
69+
val trackColorUncheckedDisabled =
70+
MainApp.getAppContext().resources.getColor(R.color.switch_track_unchecked_disabled)
71+
72+
val trackColors = intArrayOf(
73+
trackColorCheckedEnabled,
74+
trackColorCheckedDisabled,
75+
trackColorUncheckedEnabled,
76+
trackColorUncheckedDisabled
77+
)
78+
val trackColorStateList = ColorStateList(states, trackColors)
79+
80+
// setting the thumb color
81+
DrawableCompat.setTintList(switchView.thumbDrawable, thumbColorStateList)
82+
83+
// setting the track color
84+
DrawableCompat.setTintList(switchView.trackDrawable, trackColorStateList)
85+
}
86+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.nmc.android.utils
2+
3+
import android.content.res.Configuration
4+
import com.owncloud.android.MainApp
5+
import com.owncloud.android.R
6+
7+
object DisplayUtils {
8+
9+
@JvmStatic
10+
fun isShowDividerForList(): Boolean = isTablet() || isLandscapeOrientation()
11+
12+
@JvmStatic
13+
fun isTablet(): Boolean = MainApp.getAppContext().resources.getBoolean(R.bool.isTablet)
14+
15+
@JvmStatic
16+
fun isLandscapeOrientation(): Boolean =
17+
MainApp.getAppContext().resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
18+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.nmc.android.utils;
2+
3+
import android.app.Activity;
4+
import android.content.Context;
5+
import android.view.View;
6+
import android.view.inputmethod.InputMethodManager;
7+
8+
public class KeyboardUtils {
9+
10+
public static void showSoftKeyboard(Context context, View view) {
11+
view.requestFocus();
12+
InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
13+
imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
14+
}
15+
16+
public static void hideKeyboardFrom(Context context, View view) {
17+
view.clearFocus();
18+
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
19+
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
20+
}
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.nmc.android.utils
2+
3+
import android.content.Context
4+
import android.widget.ImageView
5+
import androidx.appcompat.widget.SearchView
6+
import com.owncloud.android.R
7+
8+
object SearchViewThemeUtils {
9+
fun themeSearchView(context: Context, searchView: SearchView) {
10+
val fontColor = context.resources.getColor(R.color.fontAppbar, null)
11+
val editText: SearchView.SearchAutoComplete = searchView.findViewById(R.id.search_src_text)
12+
editText.textSize = 16F
13+
editText.setTextColor(fontColor)
14+
editText.highlightColor = context.resources.getColor(R.color.et_highlight_color, null)
15+
editText.setHintTextColor(context.resources.getColor(R.color.fontSecondaryAppbar, null))
16+
val closeButton: ImageView = searchView.findViewById(R.id.search_close_btn)
17+
closeButton.setColorFilter(fontColor)
18+
val searchButton: ImageView = searchView.findViewById(R.id.search_button)
19+
searchButton.setImageResource(R.drawable.ic_search)
20+
searchButton.setColorFilter(fontColor)
21+
}
22+
}

app/src/main/java/com/owncloud/android/operations/CreateShareWithShareeOperation.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ protected RemoteOperationResult run(OwnCloudClient client) {
143143

144144
//once creating share link update other information
145145
UpdateShareInfoOperation updateShareInfoOperation = new UpdateShareInfoOperation(share, getStorageManager());
146-
updateShareInfoOperation.setExpirationDateInMillis(expirationDateInMillis);
146+
if (expirationDateInMillis > 0) {
147+
updateShareInfoOperation.setExpirationDateInMillis(expirationDateInMillis);
148+
}
147149
updateShareInfoOperation.setHideFileDownload(hideFileDownload);
148150
updateShareInfoOperation.setLabel(label);
149151

app/src/main/java/com/owncloud/android/providers/UsersAndGroupsSearchProvider.java

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,12 @@ private Cursor searchForUsersOrGroups(Uri uri) {
300300
displayName = userName;
301301
subline = (status.getMessage() == null || status.getMessage().isEmpty()) ? null :
302302
status.getMessage();
303-
Uri.Builder builder =
304-
Uri.parse("content://com.nextcloud.android.providers.UsersAndGroupsSearchProvider/icon")
303+
icon = R.drawable.ic_internal_share;
304+
305+
//Commented for NMC customization
306+
//uncomment the below code to show icon with initials
307+
/*Uri.Builder builder = Uri.parse("content://com.t_systems.android.webdav.android
308+
.providers.UsersAndGroupsSearchProvider/icon")
305309
.buildUpon();
306310
307311
builder.appendQueryParameter("shareWith", shareWith);
@@ -312,7 +316,7 @@ private Cursor searchForUsersOrGroups(Uri uri) {
312316
builder.appendQueryParameter("icon", status.getIcon());
313317
}
314318
315-
icon = builder.build();
319+
icon = builder.build();*/
316320

317321
dataUri = Uri.withAppendedPath(userBaseUri, shareWith);
318322
break;
@@ -341,12 +345,22 @@ private Cursor searchForUsersOrGroups(Uri uri) {
341345
}
342346

343347
if (displayName != null && dataUri != null) {
344-
response.newRow()
345-
.add(count++) // BaseColumns._ID
346-
.add(displayName) // SearchManager.SUGGEST_COLUMN_TEXT_1
347-
.add(subline) // SearchManager.SUGGEST_COLUMN_TEXT_2
348-
.add(icon) // SearchManager.SUGGEST_COLUMN_ICON_1
349-
.add(dataUri);
348+
//if display name is empty set sublime as primary text
349+
if (displayName.equals("")) {
350+
response.newRow()
351+
.add(count++) // BaseColumns._ID
352+
.add(subline) // SearchManager.SUGGEST_COLUMN_TEXT_1
353+
.add(displayName) // SearchManager.SUGGEST_COLUMN_TEXT_2
354+
.add(icon) // SearchManager.SUGGEST_COLUMN_ICON_1
355+
.add(dataUri);
356+
} else {
357+
response.newRow()
358+
.add(count++) // BaseColumns._ID
359+
.add(displayName) // SearchManager.SUGGEST_COLUMN_TEXT_1
360+
.add(subline) // SearchManager.SUGGEST_COLUMN_TEXT_2
361+
.add(icon) // SearchManager.SUGGEST_COLUMN_ICON_1
362+
.add(dataUri);
363+
}
350364
}
351365
}
352366

@@ -428,7 +442,8 @@ public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) thr
428442
} catch (FileNotFoundException e) {
429443
Log_OC.e(TAG, "File not found: " + e.getMessage());
430444
}
431-
445+
} catch (OutOfMemoryError oome) {
446+
Log_OC.e(TAG, "Out of memory");
432447
} catch (Exception e) {
433448
Log_OC.e(TAG, "Error opening file: " + e.getMessage());
434449
}

app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,8 @@ public void onRemoteOperationFinish(RemoteOperation operation, RemoteOperationRe
377377
operation instanceof UnshareOperation ||
378378
operation instanceof SynchronizeFolderOperation ||
379379
operation instanceof UpdateShareViaLinkOperation ||
380-
operation instanceof UpdateSharePermissionsOperation
380+
operation instanceof UpdateSharePermissionsOperation ||
381+
operation instanceof UpdateShareInfoOperation
381382
) {
382383
if (result.isSuccess()) {
383384
updateFileFromDB();
@@ -787,7 +788,6 @@ private void onUpdateShareInformation(RemoteOperationResult result, @StringRes i
787788
private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation operation,
788789
RemoteOperationResult result) {
789790
FileDetailSharingFragment sharingFragment = getShareFileFragment();
790-
final Fragment fileListFragment = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_LIST_OF_FILES);
791791

792792
if (result.isSuccess()) {
793793
updateFileFromDB();
@@ -811,6 +811,8 @@ private void onCreateShareViaLinkOperationFinish(CreateShareViaLinkOperation ope
811811
sharingFragment.onUpdateShareInformation(result, file);
812812
}
813813

814+
//this has to be here to avoid the crash when creating link from inside of FileDetailSharingFragment
815+
Fragment fileListFragment = getSupportFragmentManager().findFragmentByTag(FileDisplayActivity.TAG_LIST_OF_FILES);
814816
if (fileListFragment instanceof OCFileListFragment && file != null) {
815817
((OCFileListFragment) fileListFragment).updateOCFile(file);
816818
}
@@ -901,9 +903,15 @@ protected void onNewIntent(Intent intent) {
901903
* @param shareType
902904
*/
903905
protected void doShareWith(String shareeName, ShareType shareType) {
904-
FileDetailFragment fragment = getFileDetailFragment();
906+
Fragment fragment = getFileDetailFragment();
905907
if (fragment != null) {
906-
fragment.initiateSharingProcess(shareeName, shareType);
908+
((FileDetailFragment) fragment).initiateSharingProcess(shareeName, shareType);
909+
} else {
910+
//if user sharing from Preview Image Fragment
911+
fragment = getSupportFragmentManager().findFragmentByTag(ShareActivity.TAG_SHARE_FRAGMENT);
912+
if (fragment != null) {
913+
((FileDetailSharingFragment) fragment).initiateSharingProcess(shareeName, shareType);
914+
}
907915
}
908916
}
909917

@@ -917,9 +925,15 @@ protected void doShareWith(String shareeName, ShareType shareType) {
917925
@Override
918926
public void editExistingShare(OCShare share, int screenTypePermission, boolean isReshareShown,
919927
boolean isExpiryDateShown) {
920-
FileDetailFragment fragment = getFileDetailFragment();
928+
Fragment fragment = getFileDetailFragment();
921929
if (fragment != null) {
922-
fragment.editExistingShare(share, screenTypePermission, isReshareShown, isExpiryDateShown);
930+
((FileDetailFragment) fragment).editExistingShare(share, screenTypePermission, isReshareShown, isExpiryDateShown);
931+
} else {
932+
//if user editing from Preview Image Fragment
933+
fragment = getSupportFragmentManager().findFragmentByTag(ShareActivity.TAG_SHARE_FRAGMENT);
934+
if (fragment != null) {
935+
((FileDetailSharingFragment) fragment).editExistingShare(share, screenTypePermission, isReshareShown, isExpiryDateShown);
936+
}
923937
}
924938
}
925939

@@ -930,7 +944,7 @@ public void editExistingShare(OCShare share, int screenTypePermission, boolean i
930944
public void onShareProcessClosed() {
931945
FileDetailFragment fragment = getFileDetailFragment();
932946
if (fragment != null) {
933-
fragment.showHideFragmentView(false);
947+
//do something
934948
}
935949
}
936950

0 commit comments

Comments
 (0)