Skip to content

Commit ffa7cc4

Browse files
feat(sharing): Show expiration date state in share list
Signed-off-by: Andy Scherzinger <[email protected]>
1 parent 37702f2 commit ffa7cc4

File tree

17 files changed

+1710
-72
lines changed

17 files changed

+1710
-72
lines changed

app/schemas/it.niedermann.owncloud.notes.persistence.NotesDatabase/27.json

Lines changed: 741 additions & 0 deletions
Large diffs are not rendered by default.

app/schemas/it.niedermann.owncloud.notes.persistence.NotesDatabase/28.json

Lines changed: 746 additions & 0 deletions
Large diffs are not rendered by default.

app/src/main/java/it/niedermann/owncloud/notes/branding/NotesViewThemeUtils.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import android.util.Log;
2020
import android.view.View;
2121
import android.widget.ImageView;
22+
import android.widget.LinearLayout;
2223
import android.widget.TextView;
2324

2425
import androidx.annotation.ColorInt;
@@ -28,7 +29,6 @@
2829
import androidx.appcompat.widget.SearchView;
2930
import androidx.appcompat.widget.Toolbar;
3031
import androidx.core.content.ContextCompat;
31-
import androidx.core.content.res.ResourcesCompat;
3232
import androidx.core.graphics.drawable.DrawableCompat;
3333

3434
import com.google.android.material.appbar.AppBarLayout;
@@ -220,6 +220,28 @@ public void themeToolbarSearchView(@NonNull SearchView searchView) {
220220
});
221221
}
222222

223+
/**
224+
* @deprecated Should be replaced with {@link com.google.android.material.search.SearchView}
225+
*/
226+
@Deprecated
227+
public void themeContentSearchView(@NonNull SearchView searchView) {
228+
withScheme(searchView, scheme -> {
229+
// hacky as no default way is provided
230+
final var editText = (AppCompatAutoCompleteTextView) searchView
231+
.findViewById(androidx.appcompat.R.id.search_src_text);
232+
final var searchPlate = (LinearLayout) searchView.findViewById(androidx.appcompat.R.id.search_plate);
233+
final var closeButton = (ImageView) searchView.findViewById(androidx.appcompat.R.id.search_close_btn);
234+
final var searchButton = (ImageView) searchView.findViewById(androidx.appcompat.R.id.search_button);
235+
editText.setHintTextColor(dynamicColor.onSurfaceVariant().getArgb(scheme));
236+
editText.setHighlightColor(dynamicColor.inverseOnSurface().getArgb(scheme));
237+
editText.setTextColor(dynamicColor.onSurface().getArgb(scheme));
238+
closeButton.setColorFilter(dynamicColor.onSurface().getArgb(scheme));
239+
searchButton.setColorFilter(dynamicColor.onSurface().getArgb(scheme));
240+
searchPlate.setBackgroundColor(dynamicColor.surfaceContainerHigh().getArgb(scheme));
241+
return searchView;
242+
});
243+
}
244+
223245
public void themeInternalLinkIcon(ImageView view) {
224246
withScheme(view, scheme -> {
225247
view

app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesDatabase.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,11 @@
5858
NotesListWidgetData.class,
5959
ShareEntity.class,
6060
Capabilities.class
61-
}, version = 27,
61+
}, version = 28,
6262
autoMigrations = {
6363
@AutoMigration(from = 25, to = 26),
6464
@AutoMigration(from = 26, to = 27),
65+
@AutoMigration(from = 27, to = 28),
6566
}
6667
)
6768
@TypeConverters({Converters.class})

app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/ShareEntity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ data class ShareEntity(
2424
val displayname_file_owner: String? = null,
2525
val uid_owner: String? = null,
2626
val displayname_owner: String? = null,
27-
val url: String? = null
27+
val url: String? = null,
28+
val expiration_date: Long? = null
2829
)

app/src/main/java/it/niedermann/owncloud/notes/share/NoteShareActivity.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@
4444

4545
import org.jetbrains.annotations.NotNull;
4646

47+
import java.text.SimpleDateFormat;
4748
import java.util.ArrayList;
4849
import java.util.Collections;
50+
import java.util.Date;
4951
import java.util.List;
5052
import java.util.concurrent.Executors;
5153
import java.util.concurrent.Future;
@@ -466,6 +468,22 @@ public void showSharingMenuActionSheet(OCShare share) {
466468
}
467469
}
468470

471+
@Override
472+
public void showShareExpirationSnackbar(OCShare share) {
473+
String expirationDescription = getString(
474+
R.string.share_expires,
475+
SimpleDateFormat.getDateInstance().format(new Date(share.getExpirationDate()))
476+
);
477+
Snackbar snackbar = Snackbar
478+
.make(binding.getRoot(), expirationDescription, Snackbar.LENGTH_LONG)
479+
.setAction(R.string.dismiss, view -> {
480+
// Clicking on empty click action will dismiss snackbar
481+
});
482+
final var util = BrandingUtil.of(BrandingUtil.readBrandMainColor(this), this);
483+
util.material.themeSnackbar(snackbar);
484+
snackbar.show();
485+
}
486+
469487
@Override
470488
public void showPermissionsDialog(OCShare share) {
471489
new QuickSharingPermissionsBottomSheetDialog(this, this, share).show();
@@ -807,12 +825,17 @@ public void applyBrand(int color) {
807825
final var util = BrandingUtil.of(color, this);
808826
util.platform.themeStatusBar(this);
809827
util.material.themeToolbar(binding.toolbar);
810-
util.androidx.themeToolbarSearchView(binding.searchView);
828+
util.notes.themeContentSearchView(binding.searchView);
829+
util.platform.colorImageView(binding.searchViewIcon, ColorRole.ON_SURFACE_VARIANT);
830+
util.platform.colorImageView(binding.pickContactEmailBtn, ColorRole.ON_SURFACE_VARIANT);
811831
util.platform.colorCircularProgressBar(binding.loadingLayoutIndicator, ColorRole.PRIMARY);
812832
util.platform.themeHorizontalProgressBar(binding.progressBar);
813833
util.platform.colorViewBackground(getWindow().getDecorView());
814834
util.platform.colorViewBackground(binding.getRoot());
815835
util.material.colorMaterialButtonPrimaryOutlined(binding.btnShareButton);
836+
util.platform.colorTextView(binding.title, ColorRole.ON_SURFACE);
837+
util.platform.colorTextView(binding.fileName, ColorRole.ON_SURFACE_VARIANT);
838+
util.notes.themeSearchCardView(binding.searchCardWrapper);
816839
}
817840

818841
@Override

app/src/main/java/it/niedermann/owncloud/notes/share/adapter/SuggestionAdapter.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,35 @@ import androidx.core.database.getIntOrNull
1919
import androidx.core.database.getStringOrNull
2020
import androidx.cursoradapter.widget.CursorAdapter
2121
import it.niedermann.owncloud.notes.R
22+
import it.niedermann.owncloud.notes.branding.BrandingUtil
23+
import it.niedermann.owncloud.notes.databinding.ItemSuggestionAdapterBinding
2224
import it.niedermann.owncloud.notes.persistence.entity.Account
2325
import it.niedermann.owncloud.notes.share.helper.AvatarLoader
2426

25-
class SuggestionAdapter(context: Context, cursor: Cursor?, private val account: Account) : CursorAdapter(context, cursor, false) {
27+
/**
28+
* [CursorAdapter] used to display search suggestions for sharees for sharing notes.
29+
*
30+
* This adapter handles the layout and binding of suggestion data, including the
31+
* display of user avatars or system icons based on the provided search cursor.
32+
*
33+
* @param context The [Context] in which the adapter is running.
34+
* @param cursor The [Cursor] from which to get the data.
35+
* @param account The [Account] used for loading authenticated avatars.
36+
*/
37+
class SuggestionAdapter(context: Context, cursor: Cursor?, private val account: Account) :
38+
CursorAdapter(context, cursor, false) {
2639
override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View {
27-
val inflater = LayoutInflater.from(context)
28-
return inflater.inflate(R.layout.item_suggestion_adapter, parent, false)
40+
val binding = ItemSuggestionAdapterBinding.inflate(LayoutInflater.from(context), parent, false)
41+
val brandingUtil = BrandingUtil.of(BrandingUtil.readBrandMainColor(parent.context), parent.context)
42+
binding.root.setBackgroundColor(brandingUtil.getScheme(parent.context).surfaceContainerHigh)
43+
return binding.root
2944
}
3045

3146
override fun bindView(view: View, context: Context, cursor: Cursor) {
3247
val suggestion =
3348
cursor.getString(cursor.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1))
3449
view.findViewById<TextView>(R.id.suggestion_text).text = suggestion
3550

36-
3751
val icon = view.findViewById<ImageView>(R.id.suggestion_icon)
3852
val iconColumn = cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1)
3953

app/src/main/java/it/niedermann/owncloud/notes/share/adapter/holder/LinkShareViewHolder.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@
77
package it.niedermann.owncloud.notes.share.adapter.holder;
88

99
import android.content.Context;
10-
import android.graphics.PorterDuff;
1110
import android.text.TextUtils;
1211
import android.view.View;
12+
import android.widget.Toast;
1313

14-
import androidx.annotation.ColorInt;
1514
import androidx.annotation.NonNull;
1615
import androidx.core.content.res.ResourcesCompat;
1716

17+
import com.google.android.material.snackbar.Snackbar;
1818
import com.nextcloud.android.common.ui.theme.utils.ColorRole;
1919
import com.owncloud.android.lib.resources.shares.OCShare;
2020
import com.owncloud.android.lib.resources.shares.ShareType;
2121

22+
import java.text.SimpleDateFormat;
23+
import java.time.Duration;
24+
import java.util.Date;
25+
2226
import it.niedermann.owncloud.notes.R;
2327
import it.niedermann.owncloud.notes.branding.BrandedViewHolder;
2428
import it.niedermann.owncloud.notes.branding.BrandingUtil;
@@ -83,6 +87,21 @@ public void bind(OCShare publicShare, ShareeListAdapterListener listener) {
8387
binding.shareByLinkContainer.setOnClickListener(v -> listener.showPermissionsDialog(publicShare));
8488
}
8589

90+
if (publicShare.getExpirationDate() > 0) {
91+
String expirationDescription = context.getString(
92+
R.string.share_expires,
93+
SimpleDateFormat.getDateInstance().format(new Date(publicShare.getExpirationDate()))
94+
);
95+
binding.expirationStatus.setContentDescription(expirationDescription);
96+
binding.expirationStatus.setVisibility(View.VISIBLE);
97+
binding.shareIconContainer.setOnClickListener(
98+
v -> listener.showShareExpirationSnackbar(publicShare)
99+
);
100+
} else {
101+
binding.expirationStatus.setContentDescription(null);
102+
binding.expirationStatus.setVisibility(View.GONE);
103+
}
104+
86105
binding.copyLink.setOnClickListener(v -> listener.copyLink(publicShare));
87106
}
88107

@@ -102,6 +121,7 @@ public void applyBrand(int color) {
102121
brandingUtil.androidx.colorPrimaryTextViewElement(binding.permissionName);
103122
brandingUtil.platform.colorTextView(binding.label, ColorRole.ON_SURFACE);
104123
brandingUtil.platform.colorImageViewBackgroundAndIcon(binding.icon);
124+
brandingUtil.platform.colorImageView(binding.expirationStatus, ColorRole.ON_PRIMARY_CONTAINER);
105125
}
106126
}
107127
}

app/src/main/java/it/niedermann/owncloud/notes/share/listener/ShareeListAdapterListener.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ public interface ShareeListAdapterListener {
1515

1616
void showSharingMenuActionSheet(OCShare share);
1717

18+
void showShareExpirationSnackbar(OCShare share);
19+
1820
void copyInternalLink();
1921

2022
void createPublicShareLink();

app/src/main/java/it/niedermann/owncloud/notes/share/model/CreateShareResponse.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,9 @@ data class CreateShareResponse(
139139

140140
@Expose
141141
@SerializedName("password")
142-
val password: String?
142+
val password: String?,
143+
144+
@Expose
145+
@SerializedName("expiration")
146+
val expirationDate: String?
143147
)

0 commit comments

Comments
 (0)