diff --git a/app/src/main/java/org/mian/gitnex/adapters/ActivitiesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ActivitiesAdapter.java index f504b64d..8864aae4 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ActivitiesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ActivitiesAdapter.java @@ -124,8 +124,6 @@ class DashboardHolder extends RecyclerView.ViewHolder { private final ImageView typeIcon; private final TextView dashText; private final LinearLayout dashTextFrame; - private LinearLayout dashboardLayoutCardsFrame; - private MaterialCardView cardLayout; private Activity activityObject; @@ -138,8 +136,9 @@ class DashboardHolder extends RecyclerView.ViewHolder { createdTime = itemView.findViewById(R.id.created_time); dashText = itemView.findViewById(R.id.text); dashTextFrame = itemView.findViewById(R.id.dash_text_frame); - dashboardLayoutCardsFrame = itemView.findViewById(R.id.dashboardLayoutCardsFrame); - cardLayout = itemView.findViewById(R.id.cardLayout); + LinearLayout dashboardLayoutCardsFrame = + itemView.findViewById(R.id.dashboardLayoutCardsFrame); + MaterialCardView cardLayout = itemView.findViewById(R.id.cardLayout); new Handler() .postDelayed( @@ -397,9 +396,11 @@ private String getString() { String content = activityObject.getContent(); String id; - if (content.trim().startsWith("[")) { + int arrayStart = content.trim().indexOf("[\""); + if (arrayStart != -1) { try { - String cleanContent = content.trim().substring(1, content.length() - 1); + String jsonPart = content.trim().substring(arrayStart); + String cleanContent = jsonPart.substring(1, jsonPart.length() - 1); String[] contentParts = cleanContent.split(",", 2); id = contentParts[0].trim(); @@ -501,30 +502,19 @@ void bindData(Activity activity, int position) { + activity.getRepo().getFullName() + ""; + String branch = + "" + + activity.getRefName() + .substring(activity.getRefName().lastIndexOf("/") + 1) + .trim() + + ""; if (activity.getContent().isEmpty()) { - String branch = - "" - + activity.getRefName() - .substring( - activity.getRefName().lastIndexOf("/") + 1) - .trim() - + ""; typeString = String.format(context.getString(R.string.createdBranch), branch); } else { - String branch = - "" - + activity.getRefName() - .substring( - activity.getRefName().lastIndexOf("/") + 1) - .trim() - + ""; typeString = String.format(context.getString(R.string.pushedTo), branch); JSONObject commitsObj = null; @@ -611,15 +601,45 @@ void bindData(Activity activity, int position) { } else if (activity.getOpType().getValue().contains("issue")) { String id; - String content; - String[] contentParts = activity.getContent().split("\\|"); - if (contentParts.length > 1) { + String content = ""; + String rawContent = activity.getContent().trim(); + + int arrayStart = rawContent.indexOf("[\""); + if (arrayStart != -1) { + try { + String jsonPart = rawContent.substring(arrayStart); + String cleanContent = jsonPart.substring(1, jsonPart.length() - 1); + String[] contentParts = cleanContent.split(",", 2); + id = contentParts[0].trim(); + + if (id.startsWith("\"") && id.endsWith("\"")) { + id = id.substring(1, id.length() - 1); + } + + if (contentParts.length > 1) { + content = contentParts[1].trim(); + if (content.startsWith("\"") && content.endsWith("\"")) { + content = content.substring(1, content.length() - 1); + } + } + } catch (Exception e) { + String[] contentParts = rawContent.split("\\|"); + id = contentParts[0]; + if (contentParts.length > 1) { + content = contentParts[1]; + } + } + } else { + String[] contentParts = rawContent.split("\\|"); id = contentParts[0]; - content = contentParts[1]; + if (contentParts.length > 1) { + content = contentParts[1]; + } + } + + if (!content.isEmpty()) { dashTextFrame.setVisibility(View.VISIBLE); dashText.setText(EmojiParser.parseToUnicode(content)); - } else { - id = contentParts[0]; } if (activity.getOpType().getValue().equalsIgnoreCase("create_issue")) { @@ -678,15 +698,45 @@ void bindData(Activity activity, int position) { } else if (activity.getOpType().getValue().contains("pull")) { String id; - String content; - String[] contentParts = activity.getContent().split("\\|"); - if (contentParts.length > 1) { + String content = ""; + String rawContent = activity.getContent().trim(); + + int arrayStart = rawContent.indexOf("[\""); + if (arrayStart != -1) { + try { + String jsonPart = rawContent.substring(arrayStart); + String cleanContent = jsonPart.substring(1, jsonPart.length() - 1); + String[] contentParts = cleanContent.split(",", 2); + id = contentParts[0].trim(); + + if (id.startsWith("\"") && id.endsWith("\"")) { + id = id.substring(1, id.length() - 1); + } + + if (contentParts.length > 1) { + content = contentParts[1].trim(); + if (content.startsWith("\"") && content.endsWith("\"")) { + content = content.substring(1, content.length() - 1); + } + } + } catch (Exception e) { + String[] contentParts = rawContent.split("\\|"); + id = contentParts[0]; + if (contentParts.length > 1) { + content = contentParts[1]; + } + } + } else { + String[] contentParts = rawContent.split("\\|"); id = contentParts[0]; - content = contentParts[1]; + if (contentParts.length > 1) { + content = contentParts[1]; + } + } + + if (!content.isEmpty()) { dashTextFrame.setVisibility(View.VISIBLE); dashText.setText(EmojiParser.parseToUnicode(content)); - } else { - id = contentParts[0]; } if (activity.getOpType().getValue().equalsIgnoreCase("create_pull_request")) { @@ -804,10 +854,36 @@ void bindData(Activity activity, int position) { } } else if (activity.getOpType().getValue().contains("branch")) { - String content; - String[] contentParts = activity.getContent().split("\\|"); - if (contentParts.length > 1) { - content = contentParts[1]; + String content = ""; + String rawContent = activity.getContent().trim(); + + int arrayStart = rawContent.indexOf("[\""); + if (arrayStart != -1) { + try { + String jsonPart = rawContent.substring(arrayStart); + String cleanContent = jsonPart.substring(1, jsonPart.length() - 1); + String[] contentParts = cleanContent.split(",", 2); + + if (contentParts.length > 1) { + content = contentParts[1].trim(); + if (content.startsWith("\"") && content.endsWith("\"")) { + content = content.substring(1, content.length() - 1); + } + } + } catch (Exception e) { + String[] contentParts = rawContent.split("\\|"); + if (contentParts.length > 1) { + content = contentParts[1]; + } + } + } else { + String[] contentParts = rawContent.split("\\|"); + if (contentParts.length > 1) { + content = contentParts[1]; + } + } + + if (!content.isEmpty()) { dashTextFrame.setVisibility(View.VISIBLE); dashText.setText(EmojiParser.parseToUnicode(content)); } diff --git a/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java index e8cd36db..001d8cbd 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/IssueCommentsAdapter.java @@ -3,6 +3,7 @@ import static org.mian.gitnex.helpers.AppUtil.isNightModeThemeDynamic; import android.annotation.SuppressLint; +import android.app.Activity; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; @@ -27,6 +28,8 @@ import android.widget.RelativeLayout; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.core.content.ContextCompat; import androidx.core.content.res.ResourcesCompat; import androidx.core.text.HtmlCompat; @@ -35,10 +38,12 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.target.CustomTarget; +import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.transition.Transition; import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.card.MaterialCardView; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -75,7 +80,7 @@ import retrofit2.Callback; /** - * @author M M Arif + * @author mmarif */ public class IssueCommentsAdapter extends RecyclerView.Adapter { @@ -102,7 +107,7 @@ public IssueCommentsAdapter( this.issuesComments = issuesCommentsMain; this.onInteractedListener = onInteractedListener; tinyDB = TinyDB.getInstance(ctx); - locale = ctx.getResources().getConfiguration().locale; + locale = ctx.getResources().getConfiguration().getLocales().get(0); this.issue = issue; } @@ -241,6 +246,8 @@ class IssueCommentViewHolder extends RecyclerView.ViewHolder { private TimelineComment issueComment; private final LinearLayout timelineDividerView; private final FrameLayout timelineLine2; + private final List> glideTargets = new ArrayList<>(); + private boolean isAttachedToWindow = false; private IssueCommentViewHolder(View view) { @@ -263,14 +270,15 @@ private IssueCommentViewHolder(View view) { String token = ((BaseActivity) context).getAccount().getAccount().getToken(); - new Handler() - .postDelayed( - () -> { - if (issueComment != null) { - getAttachments(issueComment.getId(), view, token); - } - }, - 250); + Handler handler = new Handler(); + + handler.postDelayed( + () -> { + if (issueComment != null) { + getAttachments(issueComment.getId(), view, token, this); + } + }, + 250); menu.setOnClickListener( v -> { @@ -467,6 +475,9 @@ private IssueCommentViewHolder(View view) { void bindData(TimelineComment timelineComment) { + clearGlideRequests(); + isAttachedToWindow = true; + if (timelineComment != null) { Typeface typeface = AppUtil.getTypeface(context); @@ -1139,7 +1150,6 @@ else if (issueComment.getType().equalsIgnoreCase("added_deadline") } } - // TODO pretty-print if (issueComment.getType().equalsIgnoreCase("added_deadline")) { start.setText( context.getString( @@ -1364,12 +1374,7 @@ else if (issueComment.getType().equalsIgnoreCase("pin")) { author.setText(issueComment.getUser().getLogin()); - Glide.with(context) - .load(issueComment.getUser().getAvatarUrl()) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .placeholder(R.drawable.loader_animated) - .centerCrop() - .into(avatar); + loadAvatarSafely(issueComment.getUser().getAvatarUrl(), avatar); Markdown.render( context, issueComment.getBody(), comment, issue.getRepository()); @@ -1401,9 +1406,41 @@ else if (issueComment.getType().equalsIgnoreCase("pin")) { commentView.setVisibility(View.GONE); } } + + private void loadAvatarSafely(String avatarUrl, ImageView avatarView) { + if (isActivityValid()) { + Target target = + Glide.with(context) + .load(avatarUrl) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .placeholder(R.drawable.loader_animated) + .centerCrop() + .into(avatarView); + + glideTargets.add(target); + } + } + + private boolean isActivityValid() { + if (context instanceof Activity activity) { + return !activity.isFinishing() && !activity.isDestroyed(); + } + return true; + } + + void clearGlideRequests() { + if (context != null && isActivityValid()) { + for (Target target : glideTargets) { + Glide.with(context).clear(target); + } + } + glideTargets.clear(); + isAttachedToWindow = false; + } } - private void getAttachments(Long issueIndex, View view, String token) { + private void getAttachments( + Long issueIndex, View view, String token, IssueCommentViewHolder holder) { LinearLayout attachmentFrame = view.findViewById(R.id.attachmentFrame); LinearLayout attachmentsView = view.findViewById(R.id.attachmentsView); @@ -1423,6 +1460,10 @@ public void onResponse( @NonNull Call> call, @NonNull retrofit2.Response> response) { + if (holder == null || !holder.isAttachedToWindow) { + return; + } + List attachment = response.body(); if (response.code() == 200) { @@ -1453,16 +1494,24 @@ public void onResponse( attachment.get(i).getName()) .toLowerCase())) { - Glide.with(context) - .load( - attachment.get(i).getBrowserDownloadUrl() - + "?token=" - + token) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .placeholder(R.drawable.loader_animated) - .centerCrop() - .error(R.drawable.ic_close) - .into(attachmentView); + if (holder.isActivityValid()) { + Target target = + Glide.with(context) + .load( + attachment + .get(i) + .getBrowserDownloadUrl() + + "?token=" + + token) + .diskCacheStrategy( + DiskCacheStrategy.ALL) + .placeholder(R.drawable.loader_animated) + .centerCrop() + .error(R.drawable.ic_close) + .into(attachmentView); + + holder.glideTargets.add(target); + } attachmentsView.addView(materialCardView); attachmentView.setLayoutParams(paramsAttachment); @@ -1475,7 +1524,8 @@ public void onResponse( attachment .get(finalI1) .getBrowserDownloadUrl(), - token)); + token, + holder)); } else { @@ -1508,7 +1558,11 @@ public void onFailure( }); } - private void imageViewDialog(String url, String token) { + private void imageViewDialog(String url, String token, IssueCommentViewHolder holder) { + + if (holder == null || !holder.isActivityValid()) { + return; + } MaterialAlertDialogBuilder materialAlertDialogBuilder = new MaterialAlertDialogBuilder( @@ -1521,28 +1575,65 @@ private void imageViewDialog(String url, String token) { materialAlertDialogBuilder.setNeutralButton(context.getString(R.string.close), null); - Glide.with(context) - .asBitmap() - .load(url + "?token=" + token) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .placeholder(R.drawable.loader_animated) - .centerCrop() - .error(R.drawable.ic_close) - .dontAnimate() - .into( - new CustomTarget() { - @Override - public void onResourceReady( - @NonNull Bitmap resource, - Transition transition) { - imageViewDialogBinding.imageView.setImageBitmap(resource); - imageViewDialogBinding.imageView.buildDrawingCache(); - } + CustomTarget target = + new CustomTarget() { + @Override + public void onResourceReady( + @NonNull Bitmap resource, Transition transition) { + if (holder.isAttachedToWindow) { + imageViewDialogBinding.imageView.setImageBitmap(resource); + imageViewDialogBinding.imageView.buildDrawingCache(); + } + } + + @Override + public void onLoadCleared(Drawable placeholder) { + if (holder.isAttachedToWindow) { + imageViewDialogBinding.imageView.setImageDrawable(placeholder); + } + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + super.onLoadFailed(errorDrawable); + if (holder.isAttachedToWindow) { + imageViewDialogBinding.imageView.setImageDrawable(errorDrawable); + } + } + }; + + holder.glideTargets.add(target); + + if (holder.isActivityValid()) { + Glide.with(context) + .asBitmap() + .load(url + "?token=" + token) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .placeholder(R.drawable.loader_animated) + .error(R.drawable.ic_close) + .dontAnimate() + .into(target); + } - @Override - public void onLoadCleared(Drawable placeholder) {} - }); + AlertDialog dialog = materialAlertDialogBuilder.create(); + + dialog.setOnDismissListener( + dialogInterface -> { + if (holder.isActivityValid()) { + Glide.with(context).clear(target); + holder.glideTargets.remove(target); + } + }); - materialAlertDialogBuilder.create().show(); + dialog.show(); + } + + @Override + public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) { + super.onViewRecycled(holder); + + if (holder instanceof IssueCommentViewHolder) { + ((IssueCommentViewHolder) holder).clearGlideRequests(); + } } }