diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/ImageDescriptionSheet.java b/mastodon/src/main/java/org/joinmastodon/android/ui/ImageDescriptionSheet.java
new file mode 100644
index 000000000..fa2ab5338
--- /dev/null
+++ b/mastodon/src/main/java/org/joinmastodon/android/ui/ImageDescriptionSheet.java
@@ -0,0 +1,87 @@
+package org.joinmastodon.android.ui;
+
+import android.app.Activity;
+import android.graphics.Typeface;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+
+import org.joinmastodon.android.R;
+import org.joinmastodon.android.model.Attachment;
+import org.joinmastodon.android.ui.utils.UiUtils;
+
+import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
+import me.grishka.appkit.utils.V;
+import me.grishka.appkit.views.BottomSheet;
+import me.grishka.appkit.views.UsableRecyclerView;
+
+public class ImageDescriptionSheet extends BottomSheet{
+ private UsableRecyclerView list;
+
+ public ImageDescriptionSheet(@NonNull Activity activity, Attachment attachment){
+ super(activity);
+
+ View handleView=new View(activity);
+ handleView.setBackgroundResource(R.drawable.bg_bottom_sheet_handle);
+ ViewGroup handle=new FrameLayout(activity);
+ handle.addView(handleView);
+ handle.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(24)));
+
+ TextView textView = new TextView(activity);
+ if (attachment.description == null || attachment.description.isEmpty()) {
+ textView.setText(R.string.media_no_description);
+ textView.setTypeface(null, Typeface.ITALIC);
+ } else {
+ textView.setText(attachment.description);
+ textView.setTextIsSelectable(true);
+ }
+
+ TextView heading=new TextView(activity);
+ heading.setText(R.string.image_description);
+ heading.setAllCaps(true);
+ heading.setTypeface(null, Typeface.BOLD);
+ heading.setPadding(0, V.dp(24), 0, V.dp(8));
+
+ LinearLayout linearLayout = new LinearLayout(activity);
+ linearLayout.setOrientation(LinearLayout.VERTICAL);
+ linearLayout.setPadding(V.dp(24), 0, V.dp(24), 0);
+ linearLayout.addView(heading);
+ linearLayout.addView(textView);
+
+ FrameLayout layout=new FrameLayout(activity);
+ layout.addView(handle);
+ layout.addView(linearLayout);
+
+ list=new UsableRecyclerView(activity);
+ list.setLayoutManager(new LinearLayoutManager(activity));
+ list.setBackgroundResource(R.drawable.bg_bottom_sheet);
+ list.setAdapter(new SingleViewRecyclerAdapter(layout));
+ list.setClipToPadding(false);
+
+ setContentView(list);
+ setNavigationBarBackground(new ColorDrawable(UiUtils.getThemeColor(activity, R.attr.colorWindowBackground)), !UiUtils.isDarkTheme());
+ }
+
+ @Override
+ protected void onWindowInsetsUpdated(WindowInsets insets){
+ if(Build.VERSION.SDK_INT>=29){
+ int tappableBottom=insets.getTappableElementInsets().bottom;
+ int insetBottom=insets.getSystemWindowInsetBottom();
+ if(tappableBottom==0 && insetBottom>0){
+ list.setPadding(0, 0, 0, V.dp(48)-insetBottom);
+ }else{
+ list.setPadding(0, 0, 0, V.dp(24));
+ }
+ }else{
+ list.setPadding(0, 0, 0, V.dp(24));
+ }
+ }
+}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/photoviewer/PhotoViewer.java b/mastodon/src/main/java/org/joinmastodon/android/ui/photoviewer/PhotoViewer.java
index d9c0c8334..0e128d53a 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/ui/photoviewer/PhotoViewer.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/ui/photoviewer/PhotoViewer.java
@@ -19,6 +19,7 @@ import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaScannerConnection;
import android.net.Uri;
+import android.opengl.Visibility;
import android.os.Build;
import android.os.Environment;
import android.os.SystemClock;
@@ -39,6 +40,7 @@ import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.PopupWindow;
import android.widget.ProgressBar;
import android.widget.SeekBar;
import android.widget.TextView;
@@ -48,12 +50,14 @@ import android.widget.Toolbar;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.model.Attachment;
+import org.joinmastodon.android.ui.ImageDescriptionSheet;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -69,6 +73,7 @@ import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V;
+import me.grishka.appkit.views.BottomSheet;
import me.grishka.appkit.views.FragmentRootLinearLayout;
import okio.BufferedSink;
import okio.Okio;
@@ -97,6 +102,7 @@ public class PhotoViewer implements ZoomPanView.Listener{
private TextView videoTimeView;
private ImageButton videoPlayPauseButton;
private View videoControls;
+ private MenuItem imageDescriptionButton;
private boolean uiVisible=true;
private AudioManager.OnAudioFocusChangeListener audioFocusListener=this::onAudioFocusChanged;
private Runnable uiAutoHider=()->{
@@ -174,11 +180,24 @@ public class PhotoViewer implements ZoomPanView.Listener{
toolbarWrap=uiOverlay.findViewById(R.id.toolbar_wrap);
toolbar=uiOverlay.findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(v->onStartSwipeToDismissTransition(0));
- toolbar.getMenu().add(R.string.download).setIcon(R.drawable.ic_fluent_arrow_download_24_regular).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
- toolbar.setOnMenuItemClickListener(item->{
- saveCurrentFile();
- return true;
- });
+ imageDescriptionButton = toolbar.getMenu()
+ .add(R.string.image_description)
+ .setIcon(R.drawable.ic_fluent_image_alt_text_24_regular)
+ .setVisible(attachments.get(pager.getCurrentItem()).description != null
+ && !attachments.get(pager.getCurrentItem()).description.isEmpty())
+ .setOnMenuItemClickListener(item -> {
+ new ImageDescriptionSheet(activity,attachments.get(pager.getCurrentItem())).show();
+ return true;
+ });
+ imageDescriptionButton.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
+ toolbar.getMenu()
+ .add(R.string.download)
+ .setIcon(R.drawable.ic_fluent_arrow_download_24_regular)
+ .setOnMenuItemClickListener(item -> {
+ saveCurrentFile();
+ return true;
+ })
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
uiOverlay.setAlpha(0f);
videoControls=uiOverlay.findViewById(R.id.video_player_controls);
videoSeekBar=uiOverlay.findViewById(R.id.seekbar);
@@ -374,6 +393,8 @@ public class PhotoViewer implements ZoomPanView.Listener{
private void onPageChanged(int index){
currentIndex=index;
Attachment att=attachments.get(index);
+ imageDescriptionButton.setVisible(att.description != null && !att.description.isEmpty());
+ toolbar.invalidate();
V.setVisibilityAnimated(videoControls, att.type==Attachment.Type.VIDEO ? View.VISIBLE : View.GONE);
if(att.type==Attachment.Type.VIDEO){
videoSeekBar.setSecondaryProgress(0);
diff --git a/mastodon/src/main/res/drawable/ic_fluent_image_alt_text_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_image_alt_text_24_regular.xml
new file mode 100644
index 000000000..037d623c3
--- /dev/null
+++ b/mastodon/src/main/res/drawable/ic_fluent_image_alt_text_24_regular.xml
@@ -0,0 +1,3 @@
+
+
+
diff --git a/mastodon/src/main/res/values-de-rDE/strings.xml b/mastodon/src/main/res/values-de-rDE/strings.xml
index 0f904471a..f3a3efca3 100644
--- a/mastodon/src/main/res/values-de-rDE/strings.xml
+++ b/mastodon/src/main/res/values-de-rDE/strings.xml
@@ -203,6 +203,7 @@
Bestätigungs-E-Mail gesendet
Was gibt\'s Neues?
Inhaltswarnung
+ Bildbeschreibung
Füge eine Bildbeschreibung hinzu…
Upload erneut versuchen
Fehler beim Hochladen des Bildes
@@ -316,7 +317,7 @@
Genehmigt Folgende manuell
Aktuelles Konto
%s ausloggen
-
+
- %,d Follower
- %,d Follower
diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml
index 9f0b83b2e..4a80c45f5 100644
--- a/mastodon/src/main/res/values/strings.xml
+++ b/mastodon/src/main/res/values/strings.xml
@@ -209,6 +209,7 @@
Type or paste what\'s on your mind
Content warning
Add image description…
+ Image description
Retry upload
Image failed to upload
Video failed to upload