Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attached files caption #567

Merged
merged 12 commits into from Mar 6, 2024
Expand Up @@ -47,6 +47,7 @@
import org.thunderdog.challegram.core.Media;
import org.thunderdog.challegram.data.InlineResult;
import org.thunderdog.challegram.data.InlineResultCommon;
import org.thunderdog.challegram.data.TD;
import org.thunderdog.challegram.loader.ImageFile;
import org.thunderdog.challegram.loader.ImageGalleryFile;
import org.thunderdog.challegram.navigation.HeaderView;
Expand All @@ -61,6 +62,7 @@
import org.thunderdog.challegram.tool.UI;
import org.thunderdog.challegram.ui.ListItem;
import org.thunderdog.challegram.ui.SettingsAdapter;
import org.thunderdog.challegram.util.HapticMenuHelper;
import org.thunderdog.challegram.util.Permissions;

import java.io.File;
Expand Down Expand Up @@ -110,18 +112,26 @@ public void onMenuItemPressed (int id, View view) {
private void showSystemPicker (boolean forceDownloads) {
RunnableData<Set<Uri>> callback = uris -> {
if (uris != null && !uris.isEmpty()) {
List<String> files = new ArrayList<>(uris.size());
for (Uri uri : uris) {
String filePath = U.tryResolveFilePath(uri);
if (!StringUtils.isEmpty(filePath) && U.canReadFile(filePath)) {
files.add(filePath);
} else {
files.add(uri.toString());
Media.instance().post(() -> {
final ArrayList<InlineResult<?>> results = new ArrayList<>(uris.size());
final TD.FileInfo fileInfo = new TD.FileInfo();
for (Uri uri : uris) {
String filePath = U.tryResolveFilePath(uri);
if (!StringUtils.isEmpty(filePath) && U.canReadFile(filePath)) {
results.add(createItem(context, tdlib, new File(filePath), null));
} else {
final String path = uri.toString();
TD.createInputFile(path, null, fileInfo);
results.add(createItem(context, tdlib, path, R.drawable.baseline_insert_drive_file_24, fileInfo.title, Strings.buildSize(fileInfo.knownSize)));
}
}
}
mediaLayout.pickDateOrProceed((sendOptions, disableMarkdown) ->
mediaLayout.sendFilesMixed(mediaLayout.getTarget() != null ? mediaLayout.getTarget().getAttachButton() : null, files, null, sendOptions, false)
);
UI.post(() -> {
if (mediaLayout.getTarget() != null && mediaLayout.getTarget().isFocused()) {
mediaLayout.getTarget().setFilesToAttach(results, false);
mediaLayout.hide(false);
}
});
});
}
};
final Intent intent = new Intent(Intent.ACTION_GET_CONTENT)
Expand Down Expand Up @@ -235,14 +245,14 @@ private void navigateToPath (final View view, final String currentPath, final St
final boolean isRemovable = Environment.isExternalStorageRemovable();
StatFs fs = new StatFs(environmentPath);
String text = Lang.getString(R.string.FreeXofY, Strings.buildSize(StorageUtils.freeMemorySize(fs)), Strings.buildSize(StorageUtils.totalMemorySize(fs)));
InlineResultCommon internalStorage = new InlineResultCommon(context, tdlib, KEY_FOLDER + environmentPath, ColorId.fileAttach, isRemovable ? R.drawable.baseline_sd_storage_24 : R.drawable.baseline_storage_24, Lang.getString(isRemovable ? R.string.SdCard : R.string.InternalStorage), text);
InlineResultCommon internalStorage = new InlineResultCommon(context, tdlib, KEY_FOLDER + environmentPath, ColorId.fileAttach, isRemovable ? R.drawable.baseline_sd_storage_24 : R.drawable.baseline_storage_24, Lang.getString(isRemovable ? R.string.SdCard : R.string.InternalStorage), text).setDisableProgressInteract(true);
items.add(createItem(internalStorage, R.id.btn_internalStorage));
}

final ArrayList<String> externalStorageFiles = U.getExternalStorageDirectories(baseExternalDir != null ? baseExternalDir.getPath() : null, false);
if (externalStorageFiles != null) {
for (String dir : externalStorageFiles) {
InlineResultCommon internalStorage = new InlineResultCommon(context, tdlib, KEY_FOLDER + dir, ColorId.fileAttach, R.drawable.baseline_storage_24, Lang.getString(R.string.Storage), dir);
InlineResultCommon internalStorage = new InlineResultCommon(context, tdlib, KEY_FOLDER + dir, ColorId.fileAttach, R.drawable.baseline_storage_24, Lang.getString(R.string.Storage), dir).setDisableProgressInteract(true);
items.add(createItem(internalStorage, R.id.btn_internalStorage));
}
}
Expand Down Expand Up @@ -299,7 +309,7 @@ else if (foldersCount != 0)
text = Lang.plural(R.string.xFolders, foldersCount);
else
text = Lang.plural(R.string.xFiles, filesCount);
InlineResultCommon rootDirectory = new InlineResultCommon(context, tdlib, KEY_FOLDER + rootDir.getPath(), ColorId.fileAttach, R.drawable.baseline_folder_24, Lang.getString(R.string.RootDirectory), text);
InlineResultCommon rootDirectory = new InlineResultCommon(context, tdlib, KEY_FOLDER + rootDir.getPath(), ColorId.fileAttach, R.drawable.baseline_folder_24, Lang.getString(R.string.RootDirectory), text).setDisableProgressInteract(true);
items.add(createItem(rootDirectory, R.id.btn_folder));
hasRoot = true;
}
Expand Down Expand Up @@ -688,7 +698,7 @@ public Result act () {

for (FileEntry entry : entries) {
final String subtitle = Lang.getFileTimestamp(Math.max(entry.getDateModified(), entry.getDateAdded()), TimeUnit.SECONDS, entry.getSize());
InlineResultCommon fileItem = new InlineResultCommon(context, tdlib, new File(entry.getData()), entry.getDisplayName(), subtitle, entry, false);
InlineResultCommon fileItem = new InlineResultCommon(context, tdlib, new File(entry.getData()), entry.getDisplayName(), subtitle, entry, false).setDisableProgressInteract(true);
items.add(createItem(fileItem, R.id.btn_file));
}

Expand Down Expand Up @@ -757,7 +767,7 @@ public Result act () {
items.add(createItem(result, R.id.btn_folder_upper));

for (MusicEntry entry : entries) {
items.add(new ListItem(ListItem.TYPE_CUSTOM_INLINE, R.id.btn_file).setData(new InlineResultCommon(context, tdlib, entry, MediaBottomFilesController.this)));
items.add(new ListItem(ListItem.TYPE_CUSTOM_INLINE, R.id.btn_file).setData(new InlineResultCommon(context, tdlib, entry, MediaBottomFilesController.this).setDisableProgressInteract(true)));
}

return new Result(items, true);
Expand Down Expand Up @@ -958,12 +968,12 @@ public static InlineResultCommon createItem (BaseActivity context, Tdlib tdlib,

public static InlineResultCommon createItem (BaseActivity context, Tdlib tdlib, File file, @Nullable Object tag, String title, long lastModifiedTime, String subtitle, boolean isFolder) {
if (file.isDirectory()) {
return new InlineResultCommon(context, tdlib, KEY_FOLDER + file.getPath(), ColorId.fileAttach, R.drawable.baseline_folder_24, file.getName(), Lang.getString(R.string.Folder));
return new InlineResultCommon(context, tdlib, KEY_FOLDER + file.getPath(), ColorId.fileAttach, R.drawable.baseline_folder_24, file.getName(), Lang.getString(R.string.Folder)).setDisableProgressInteract(true);
} else {
if (subtitle == null) {
subtitle = Lang.getFileTimestamp(lastModifiedTime, TimeUnit.MILLISECONDS, file.length());
}
return new InlineResultCommon(context, tdlib, file, title != null ? title : file.getName(), subtitle, tag, isFolder);
return new InlineResultCommon(context, tdlib, file, title != null ? title : file.getName(), subtitle, tag, isFolder).setDisableProgressInteract(true);
}
}

Expand All @@ -972,7 +982,7 @@ public static InlineResultCommon createItem (BaseActivity context, Tdlib tdlib,
}

public static InlineResultCommon createItem (BaseActivity context, Tdlib tdlib, String path, int iconRes, String title, String subtitle) {
return new InlineResultCommon(context, tdlib, path, ColorId.fileAttach, iconRes, title, subtitle);
return new InlineResultCommon(context, tdlib, path, ColorId.fileAttach, iconRes, title, subtitle).setDisableProgressInteract(true);
}

public static ListItem createItem (InlineResult<?> result, int id) {
Expand Down Expand Up @@ -1008,6 +1018,22 @@ public boolean onBackPressed (boolean fromTop) {
return false;
}

@Override
protected void addCustomItems (View view, @NonNull List<HapticMenuHelper.MenuItem> hapticItems) {
hapticItems.add(0, new HapticMenuHelper.MenuItem(R.id.btn_addCaption, Lang.getString(R.string.AddCaption), R.drawable.baseline_file_caption_24).setOnClickListener(this::onHapticMenuItemClick));
}

private boolean onHapticMenuItemClick (View view, View parentView, HapticMenuHelper.MenuItem item) {
final int id = view.getId();
if (id == R.id.btn_addCaption) {
if (mediaLayout.getTarget() != null) {
mediaLayout.getTarget().setFilesToAttach(new ArrayList<>(selectedItems), true);
mediaLayout.hide(false);
}
}
return true;
}

@Override
public void onClick (View v) {
if (v.getId() == R.id.btn_folder_upper) {
Expand All @@ -1027,15 +1053,9 @@ public void onClick (View v) {
if (inFileSelectMode) {
selectItem(item, result);
} else {
switch (result.getType()) {
case InlineResult.TYPE_AUDIO: {
mediaLayout.sendMusic(v, (MusicEntry) result.getTag());
break;
}
case InlineResult.TYPE_DOCUMENT: {
mediaLayout.sendFile(v, result.getId());
break;
}
if (mediaLayout.getTarget() != null) {
mediaLayout.getTarget().setFilesToAttach(new ArrayList<>(Collections.singleton(result)), false);
mediaLayout.hide(false);
}
}
} else if (itemId == R.id.btn_bucket) {
Expand Down
Expand Up @@ -395,7 +395,7 @@ public boolean onInterceptTouchEvent (MotionEvent ev) {
return getVisibility() != View.VISIBLE || getAlpha() == 0f || super.onInterceptTouchEvent(ev);
}

private int detectRecyclerTopEdge () {
public int detectRecyclerTopEdge () {
int top;
LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
int i = manager.findFirstVisibleItemPosition();
Expand Down Expand Up @@ -487,7 +487,7 @@ public void addItems (TdlibDelegate delegate, @Nullable ArrayList<InlineResult<?
private boolean animationNeeded;
private float showFactor;

private float getVisibleFactor () {
public float getVisibleFactor () {
return showFactor * (1f - hideFactor);
}

Expand Down Expand Up @@ -543,14 +543,18 @@ private void animateFactor (float factor, boolean byLayout) {
private BoolAnimator hideAnimator;

public void setHidden (boolean isHidden) {
setHidden(isHidden, true);
}

public void setHidden (boolean isHidden, boolean animated) {
if (hideAnimator == null) {
if (!isHidden) {
return;
}
hideAnimator = new BoolAnimator(ANIMATOR_HIDE, this, AnimatorUtils.DECELERATE_INTERPOLATOR, 180l);
}
calculateTranslateY();
hideAnimator.setValue(isHidden, showFactor > 0f);
hideAnimator.setValue(isHidden, animated && showFactor > 0f);
}

@Override
Expand Down Expand Up @@ -666,7 +670,7 @@ private void setSpanCount (int width, int height) {

private ArrayList<InlineResult<?>> currentItems;

private void removeItem (InlineResult<?> result) {
public void removeItem (InlineResult<?> result) {
if (currentItems == null) {
return;
}
Expand Down Expand Up @@ -849,10 +853,22 @@ public void updatePosition (boolean needTranslate) {
@Override
public int provideHeight () {
int height = offsetProvider != null ? offsetProvider.provideParentHeight(this) : ((BaseActivity) getContext()).getContentView().getMeasuredHeight(); // - measureItemsHeight();
height -= Math.min(measureItemsHeight(), Screen.smallestActualSide() / 2);
height -= getMinItemsHeight();
return Math.max(0, height);
}

public int getMinItemsHeight () {
return Math.min(measureItemsHeight(), getHeightLimit());
}

public static int getHeightLimit () {
return Screen.smallestActualSide() / 2;
}

public ArrayList<InlineResult<?>> getCurrentItems () {
return currentItems;
}

// Switch pm utils

private CancellableResultHandler switchPmHandler;
Expand Down Expand Up @@ -902,11 +918,11 @@ public void processResult (final TdApi.Object object) {
// Interfaces

public interface PickListener {
void onHashtagPick (InlineResultHashtag result);
void onMentionPick (InlineResultMention result, @Nullable String usernamelessText);
void onCommandPick (InlineResultCommand result, boolean isLongPress);
void onEmojiSuggestionPick (InlineResultEmojiSuggestion result);
void onInlineQueryResultPick (InlineResult<?> result);
default void onHashtagPick (InlineResultHashtag result) {}
default void onMentionPick (InlineResultMention result, @Nullable String usernamelessText) {}
default void onCommandPick (InlineResultCommand result, boolean isLongPress) {}
default void onEmojiSuggestionPick (InlineResultEmojiSuggestion result) {}
default void onInlineQueryResultPick (InlineResult<?> result) {}
}

private PickListener listener;
Expand Down
Expand Up @@ -300,6 +300,10 @@ public final void prepare (int width) {
}
}

public final void rebuildLayout () {
layoutInternal(lastLayoutWidth);
}

private int lastLayoutWidth;

public final void layout (int width, ComplexReceiver receiver) {
Expand Down
Expand Up @@ -61,6 +61,7 @@

import me.vkryl.android.AnimatorUtils;
import me.vkryl.android.animator.FactorAnimator;
import me.vkryl.android.util.ClickHelper;
import me.vkryl.core.ColorUtils;
import me.vkryl.core.MathUtils;
import me.vkryl.core.StringUtils;
Expand All @@ -73,6 +74,7 @@ public class InlineResultCommon extends InlineResult<TdApi.InlineQueryResult> im

private FileProgressComponent fileProgress;
private boolean disableProgressInteract;
private boolean needCloseButton;
private TdApi.File targetFile;

private static final float AVATAR_PLACEHOLDER_RADIUS = 25f;
Expand Down Expand Up @@ -534,12 +536,33 @@ protected void layoutInternal (int contentWidth) {
if (isTrack()) {
lastAvailWidth -= Screen.dp(16f) + Screen.dp(23f) + Screen.dp(9f);
}
if (needCloseButton) {
lastAvailWidth -= Screen.dp(36);
}
trimmedTitle = !StringUtils.isEmpty(title) ? new Text.Builder(title, lastAvailWidth, Paints.getTitleStyleProvider(), TextColorSets.Regular.NORMAL).singleLine().allBold().build() : null;
trimmedDesc = !StringUtils.isEmpty(description) ? new Text.Builder(description, lastAvailWidth, Paints.getSubtitleStyleProvider(), TextColorSets.Regular.LIGHT).singleLine().build() : null;
}

public InlineResultCommon setDisableProgressInteract (boolean disableProgressInteract) {
this.disableProgressInteract = disableProgressInteract;
return this;
}

public void setNeedCloseButton (boolean needCloseButton) {
this.needCloseButton = needCloseButton;
}

private ClickHelper clickHelper;

public void setClickHelper (ClickHelper clickHelper) {
this.clickHelper = clickHelper;
}

@Override
public boolean onTouchEvent (View view, MotionEvent e) {
if (clickHelper != null && clickHelper.onTouchEvent(view, e)) {
return true;
}
return !disableProgressInteract && fileProgress != null && fileProgress.onTouchEvent(view, e);
}

Expand Down Expand Up @@ -606,6 +629,11 @@ protected void drawInternal (CustomResultView view, Canvas c, ComplexReceiver re
fileProgress.draw(view, c);
}

if (needCloseButton) {
Drawable drawable = view.getSparseDrawable(R.drawable.baseline_close_20, ColorId.NONE);
Drawables.draw(c, drawable, viewWidth - Screen.dp(11) - drawable.getMinimumWidth(), rectF.centerY() - drawable.getMinimumHeight() / 2f, Paints.getIconGrayPorterDuffPaint());
}

if (trimmedTitle != null) {
int textLeft = Screen.dp(11f) + Screen.dp(50f) + Screen.dp(15f);
trimmedTitle.draw(c, textLeft, startY + getPaddingVertical() + Screen.dp(5f));
Expand Down