mirror of
https://codeberg.org/gitnex/GitNex.git
synced 2024-12-16 15:48:13 +08:00
Add Issue/Comment Reactions (#557)
Minor performance improvements. Merge branch 'master' of https://codeberg.org/gitnex/GitNex into issue-reactions Improving color of selected elements. First, fully working implementation of reactions. Merge branch 'master' of https://codeberg.org/gitnex/GitNex into issue-reactions Conflicts: app/src/main/res/layout/bottom_sheet_issue_comments.xml app/src/main/res/layout/list_issue_comments.xml (Hopefully) fixing merge issues. Merge branch 'master' of https://codeberg.org/gitnex/GitNex into issue-reactions Conflicts: app/src/main/java/org/mian/gitnex/interfaces/ApiInterface.java app/src/main/res/layout/activity_issue_detail.xml app/src/main/res/layout/bottom_sheet_issue_comments.xml app/src/main/res/layout/bottom_sheet_single_issue.xml app/src/main/res/values/colors.xml Moving reactions below time frame on comments. Merge branch 'master' into layout-reactions Add IssueReactions Merge remote-tracking branch 'origin/layout-reactions' into layout-reactions Merge branch 'master' of https://gitea.com/gitnex/GitNex into layout-reactions Merge branch 'master' into layout-reactions Applying to pulls and issues. Merge branch 'master' of https://gitea.com/gitnex/GitNex into layout-reactions Providing external layouts. Some improvements. Adding comment emote indications. Adding circle around emotes. Adding some padding. First tests. Co-authored-by: opyale <opyale@noreply.gitea.io> Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: 6543 <6543@noreply.gitea.io> Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/557 Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
This commit is contained in:
parent
f97f668363
commit
ade7b797f1
@ -19,9 +19,18 @@
|
||||
<JetCodeStyleSettings>
|
||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||
<value>
|
||||
<package name="java.util" withSubpackages="false" static="false" />
|
||||
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
|
||||
<package name="io.ktor" withSubpackages="true" static="false" />
|
||||
<package name="java.util" alias="false" withSubpackages="false" />
|
||||
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
|
||||
<package name="io.ktor" alias="false" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
<option name="PACKAGES_IMPORT_LAYOUT">
|
||||
<value>
|
||||
<package name="" alias="false" withSubpackages="true" />
|
||||
<package name="java" alias="false" withSubpackages="true" />
|
||||
<package name="javax" alias="false" withSubpackages="true" />
|
||||
<package name="kotlin" alias="false" withSubpackages="true" />
|
||||
<package name="" alias="true" withSubpackages="true" />
|
||||
</value>
|
||||
</option>
|
||||
</JetCodeStyleSettings>
|
||||
|
@ -89,5 +89,6 @@ Thanks to all the open source libraries, contributors and donators.
|
||||
- Ge0rg/memorizingTrustManager
|
||||
- Dimezis/blurView
|
||||
- Mikaelhg/urlbuilder
|
||||
- emoji-java
|
||||
|
||||
[Follow me on Fediverse - mastodon.social/@mmarif](https://mastodon.social/@mmarif)
|
||||
|
@ -38,8 +38,10 @@ android {
|
||||
abortOnError false
|
||||
}
|
||||
compileOptions {
|
||||
targetCompatibility = "8"
|
||||
sourceCompatibility = "8"
|
||||
coreLibraryDesugaringEnabled true
|
||||
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
defaultConfig{
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
@ -60,7 +62,7 @@ dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'
|
||||
implementation 'com.google.android.material:material:1.3.0-alpha03'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.2'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||
implementation "androidx.legacy:legacy-support-v4:1.0.0"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
|
||||
testImplementation 'junit:junit:4.13.1'
|
||||
@ -108,5 +110,7 @@ dependencies {
|
||||
implementation "androidx.work:work-runtime:$work_version"
|
||||
implementation "com.eightbitlab:blurview:1.6.4"
|
||||
implementation "io.mikael:urlbuilder:2.0.9"
|
||||
implementation 'com.vdurmont:emoji-java:5.1.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.0'
|
||||
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ import org.mian.gitnex.models.Labels;
|
||||
import org.mian.gitnex.models.UpdateIssueAssignees;
|
||||
import org.mian.gitnex.models.WatchInfo;
|
||||
import org.mian.gitnex.viewmodels.IssueCommentsViewModel;
|
||||
import org.mian.gitnex.views.ReactionList;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
@ -208,6 +209,10 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
|
||||
|
||||
switch(text) {
|
||||
|
||||
case "onResume":
|
||||
onResume();
|
||||
break;
|
||||
|
||||
case "showLabels":
|
||||
showLabels();
|
||||
break;
|
||||
@ -519,7 +524,13 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
|
||||
viewBinding.divider.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
adapter = new IssueCommentsAdapter(ctx, issueCommentsMain, getSupportFragmentManager(), this::onResume);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("repoOwner", repoOwner);
|
||||
bundle.putString("repoName", repoName);
|
||||
bundle.putInt("issueNumber", issueIndex);
|
||||
|
||||
adapter = new IssueCommentsAdapter(ctx, bundle, issueCommentsMain, getSupportFragmentManager(), this::onResume);
|
||||
|
||||
viewBinding.recyclerView.setAdapter(adapter);
|
||||
|
||||
});
|
||||
@ -718,6 +729,15 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
|
||||
.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToastDateFormat(singleIssue.getCreated_at()), ctx));
|
||||
}
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("repoOwner", repoOwner);
|
||||
bundle.putString("repoName", repoName);
|
||||
bundle.putInt("issueId", singleIssue.getNumber());
|
||||
|
||||
ReactionList reactionList = new ReactionList(ctx, bundle);
|
||||
viewBinding.commentReactionBadges.removeAllViews();
|
||||
viewBinding.commentReactionBadges.addView(reactionList);
|
||||
|
||||
if(singleIssue.getMilestone() != null) {
|
||||
|
||||
viewBinding.issueMilestone.setVisibility(View.VISIBLE);
|
||||
|
@ -15,8 +15,9 @@ import android.widget.TextView;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.fragments.BottomSheetReplyFragment;
|
||||
import org.mian.gitnex.helpers.DiffTextView;
|
||||
import org.mian.gitnex.helpers.AppUtil;
|
||||
import org.mian.gitnex.models.FileDiffView;
|
||||
import org.mian.gitnex.views.DiffTextView;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentSkipListMap;
|
||||
@ -48,11 +49,11 @@ public class FilesDiffAdapter extends BaseAdapter {
|
||||
|
||||
selectedViews = new ConcurrentSkipListMap<>();
|
||||
|
||||
COLOR_ADDED = getColorFromAttribute(R.attr.diffAddedColor);
|
||||
COLOR_REMOVED = getColorFromAttribute(R.attr.diffRemovedColor);
|
||||
COLOR_NORMAL = getColorFromAttribute(R.attr.primaryBackgroundColor);
|
||||
COLOR_SELECTED = getColorFromAttribute(R.attr.diffSelectedColor);
|
||||
COLOR_FONT = getColorFromAttribute(R.attr.inputTextColor);
|
||||
COLOR_ADDED = AppUtil.getColorFromAttribute(context, R.attr.diffAddedColor);
|
||||
COLOR_REMOVED = AppUtil.getColorFromAttribute(context, R.attr.diffRemovedColor);
|
||||
COLOR_NORMAL = AppUtil.getColorFromAttribute(context, R.attr.primaryBackgroundColor);
|
||||
COLOR_SELECTED = AppUtil.getColorFromAttribute(context, R.attr.diffSelectedColor);
|
||||
COLOR_FONT = AppUtil.getColorFromAttribute(context, R.attr.inputTextColor);
|
||||
|
||||
}
|
||||
|
||||
@ -256,13 +257,4 @@ public class FilesDiffAdapter extends BaseAdapter {
|
||||
|
||||
}
|
||||
|
||||
private int getColorFromAttribute(int resid) {
|
||||
|
||||
TypedValue typedValue = new TypedValue();
|
||||
context.getTheme().resolveAttribute(resid, typedValue, true);
|
||||
|
||||
return typedValue.data;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
@ -29,6 +30,8 @@ import org.mian.gitnex.helpers.TimeHelper;
|
||||
import org.mian.gitnex.helpers.TinyDB;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.models.IssueComments;
|
||||
import org.mian.gitnex.views.ReactionList;
|
||||
import org.mian.gitnex.views.ReactionSpinner;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
@ -42,17 +45,22 @@ import retrofit2.Callback;
|
||||
public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdapter.IssueCommentViewHolder> {
|
||||
|
||||
private final Context ctx;
|
||||
private final TinyDB tinyDB;
|
||||
private final Bundle bundle;
|
||||
private final List<IssueComments> issuesComments;
|
||||
private final FragmentManager fragmentManager;
|
||||
private final BottomSheetReplyFragment.OnInteractedListener onInteractedListener;
|
||||
|
||||
public IssueCommentsAdapter(Context ctx, List<IssueComments> issuesCommentsMain, FragmentManager fragmentManager, BottomSheetReplyFragment.OnInteractedListener onInteractedListener) {
|
||||
public IssueCommentsAdapter(Context ctx, Bundle bundle, List<IssueComments> issuesCommentsMain, FragmentManager fragmentManager, BottomSheetReplyFragment.OnInteractedListener onInteractedListener) {
|
||||
|
||||
this.ctx = ctx;
|
||||
this.bundle = bundle;
|
||||
this.issuesComments = issuesCommentsMain;
|
||||
this.fragmentManager = fragmentManager;
|
||||
this.onInteractedListener = onInteractedListener;
|
||||
|
||||
tinyDB = TinyDB.getInstance(ctx);
|
||||
|
||||
}
|
||||
|
||||
class IssueCommentViewHolder extends RecyclerView.ViewHolder {
|
||||
@ -63,6 +71,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
|
||||
private final TextView author;
|
||||
private final TextView information;
|
||||
private final TextView comment;
|
||||
private final LinearLayout commentReactionBadges;
|
||||
|
||||
private IssueCommentViewHolder(View view) {
|
||||
|
||||
@ -73,12 +82,12 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
|
||||
information = view.findViewById(R.id.information);
|
||||
ImageView menu = view.findViewById(R.id.menu);
|
||||
comment = view.findViewById(R.id.comment);
|
||||
commentReactionBadges = view.findViewById(R.id.commentReactionBadges);
|
||||
|
||||
menu.setOnClickListener(v -> {
|
||||
|
||||
final Context ctx = v.getContext();
|
||||
final TinyDB tinyDb = TinyDB.getInstance(ctx);
|
||||
final String loginUid = tinyDb.getString("loginUid");
|
||||
final String loginUid = tinyDB.getString("loginUid");
|
||||
|
||||
@SuppressLint("InflateParams") View vw = LayoutInflater.from(ctx).inflate(R.layout.bottom_sheet_issue_comments, null);
|
||||
|
||||
@ -102,6 +111,24 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
|
||||
dialog.setContentView(vw);
|
||||
dialog.show();
|
||||
|
||||
LinearLayout linearLayout = vw.findViewById(R.id.commentReactionButtons);
|
||||
|
||||
Bundle bundle1 = new Bundle();
|
||||
bundle1.putAll(bundle);
|
||||
bundle1.putInt("commentId", issueComment.getId());
|
||||
|
||||
ReactionSpinner reactionSpinner = new ReactionSpinner(ctx, bundle1);
|
||||
reactionSpinner.setOnInteractedListener(() -> {
|
||||
|
||||
tinyDB.putBoolean("commentEdited", true);
|
||||
|
||||
onInteractedListener.onInteracted();
|
||||
dialog.dismiss();
|
||||
|
||||
});
|
||||
|
||||
linearLayout.addView(reactionSpinner);
|
||||
|
||||
commentMenuEdit.setOnClickListener(v1 -> {
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
@ -125,7 +152,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
|
||||
// share issue comment
|
||||
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
|
||||
sharingIntent.setType("text/plain");
|
||||
String intentHeader = tinyDb.getString("issueNumber") + ctx.getResources().getString(R.string.hash) + "issuecomment-" + issueComment.getId() + " " + tinyDb.getString("issueTitle");
|
||||
String intentHeader = tinyDB.getString("issueNumber") + ctx.getResources().getString(R.string.hash) + "issuecomment-" + issueComment.getId() + " " + tinyDB.getString("issueTitle");
|
||||
sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, intentHeader);
|
||||
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, commentUrl);
|
||||
ctx.startActivity(Intent.createChooser(sharingIntent, intentHeader));
|
||||
@ -155,7 +182,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String commenterName = issueComment.getUser().getUsername();
|
||||
|
||||
if(!commenterName.equals(tinyDb.getString("userLogin"))) {
|
||||
if(!commenterName.equals(tinyDB.getString("userLogin"))) {
|
||||
|
||||
stringBuilder.append("@").append(commenterName).append("\n\n");
|
||||
}
|
||||
@ -183,7 +210,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
|
||||
ClipboardManager clipboard = (ClipboardManager) Objects.requireNonNull(ctx).getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
assert clipboard != null;
|
||||
|
||||
ClipData clip = ClipData.newPlainText("Comment on issue #" + tinyDb.getString("issueNumber"), issueComment.getBody());
|
||||
ClipData clip = ClipData.newPlainText("Comment on issue #" + tinyDB.getString("issueNumber"), issueComment.getBody());
|
||||
clipboard.setPrimaryClip(clip);
|
||||
|
||||
dialog.dismiss();
|
||||
@ -214,10 +241,9 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
|
||||
|
||||
private void deleteIssueComment(final Context ctx, final int commentId, int position) {
|
||||
|
||||
final TinyDB tinyDb = TinyDB.getInstance(ctx);
|
||||
final String loginUid = tinyDb.getString("loginUid");
|
||||
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
|
||||
String[] repoFullName = tinyDb.getString("repoFullName").split("/");
|
||||
final String loginUid = tinyDB.getString("loginUid");
|
||||
final String instanceToken = "token " + tinyDB.getString(loginUid + "-token");
|
||||
String[] repoFullName = tinyDB.getString("repoFullName").split("/");
|
||||
|
||||
if (repoFullName.length != 2) {
|
||||
return;
|
||||
@ -307,6 +333,13 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
|
||||
|
||||
holder.information.setText(informationBuilder.toString());
|
||||
|
||||
Bundle bundle1 = new Bundle();
|
||||
bundle1.putAll(bundle);
|
||||
bundle1.putInt("commentId", issueComment.getId());
|
||||
|
||||
ReactionList reactionList = new ReactionList(ctx, bundle1);
|
||||
holder.commentReactionBadges.addView(reactionList);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -8,6 +8,7 @@ import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -20,6 +21,7 @@ import org.mian.gitnex.activities.MergePullRequestActivity;
|
||||
import org.mian.gitnex.helpers.TinyDB;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.helpers.Version;
|
||||
import org.mian.gitnex.views.ReactionSpinner;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@ -51,6 +53,29 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
|
||||
TextView subscribeIssue = v.findViewById(R.id.subscribeIssue);
|
||||
TextView unsubscribeIssue = v.findViewById(R.id.unsubscribeIssue);
|
||||
|
||||
LinearLayout linearLayout = v.findViewById(R.id.commentReactionButtons);
|
||||
|
||||
Bundle bundle1 = new Bundle();
|
||||
|
||||
String repoFullName = tinyDB.getString("repoFullName");
|
||||
String[] parts = repoFullName.split("/");
|
||||
|
||||
bundle1.putString("repoOwner", parts[0]);
|
||||
bundle1.putString("repoName", parts[1]);
|
||||
bundle1.putInt("issueId", Integer.parseInt(tinyDB.getString("issueNumber")));
|
||||
|
||||
ReactionSpinner reactionSpinner = new ReactionSpinner(ctx, bundle1);
|
||||
reactionSpinner.setOnInteractedListener(() -> {
|
||||
|
||||
tinyDB.putBoolean("singleIssueUpdate", true);
|
||||
|
||||
bmListener.onButtonClicked("onResume");
|
||||
dismiss();
|
||||
|
||||
});
|
||||
|
||||
linearLayout.addView(reactionSpinner);
|
||||
|
||||
if(tinyDB.getString("issueType").equalsIgnoreCase("Pull")) {
|
||||
|
||||
editIssue.setText(R.string.editPrText);
|
||||
|
@ -9,7 +9,9 @@ import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.util.Base64;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import androidx.annotation.ColorInt;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@ -131,6 +133,16 @@ public class AppUtil {
|
||||
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
public static int getColorFromAttribute(Context context, int resid) {
|
||||
|
||||
TypedValue typedValue = new TypedValue();
|
||||
context.getTheme().resolveAttribute(resid, typedValue, true);
|
||||
|
||||
return typedValue.data;
|
||||
|
||||
}
|
||||
|
||||
public static String customDateFormat(String customDate) {
|
||||
|
||||
String[] parts = customDate.split("-");
|
||||
|
@ -1,10 +1,5 @@
|
||||
package org.mian.gitnex.helpers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import org.mian.gitnex.R;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Resources;
|
||||
@ -12,6 +7,11 @@ import android.content.res.XmlResourceParser;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import org.mian.gitnex.R;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Author M M Arif
|
||||
@ -90,13 +90,14 @@ public class ChangeLog {
|
||||
|
||||
String changelogMessage = getChangelog(resId, res);
|
||||
|
||||
androidx.appcompat.app.AlertDialog.Builder builder = new AlertDialog.Builder(changelogActivity);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(changelogActivity);
|
||||
|
||||
builder.setTitle(R.string.changelogTitle);
|
||||
builder.setMessage(Html.fromHtml("<small>" + changelogMessage + "</small>"));
|
||||
builder.setNeutralButton(R.string.close, null);
|
||||
builder.setCancelable(false);
|
||||
builder.create();
|
||||
builder.show();
|
||||
|
||||
builder.create().show();
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,16 @@
|
||||
package org.mian.gitnex.interfaces;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import org.mian.gitnex.models.APISettings;
|
||||
import org.mian.gitnex.models.AddEmail;
|
||||
import org.mian.gitnex.models.AttachmentSettings;
|
||||
import org.mian.gitnex.models.Branches;
|
||||
import org.mian.gitnex.models.Collaborators;
|
||||
import org.mian.gitnex.models.Commits;
|
||||
import org.mian.gitnex.models.CreateIssue;
|
||||
import org.mian.gitnex.models.CreateLabel;
|
||||
import org.mian.gitnex.models.CreatePullRequest;
|
||||
import org.mian.gitnex.models.CreateStatusOption;
|
||||
import org.mian.gitnex.models.DeleteFile;
|
||||
import org.mian.gitnex.models.EditFile;
|
||||
import org.mian.gitnex.models.Emails;
|
||||
@ -15,8 +18,10 @@ import org.mian.gitnex.models.ExploreRepositories;
|
||||
import org.mian.gitnex.models.Files;
|
||||
import org.mian.gitnex.models.GiteaVersion;
|
||||
import org.mian.gitnex.models.IssueComments;
|
||||
import org.mian.gitnex.models.IssueReaction;
|
||||
import org.mian.gitnex.models.Issues;
|
||||
import org.mian.gitnex.models.Labels;
|
||||
import org.mian.gitnex.models.MarkdownOption;
|
||||
import org.mian.gitnex.models.MergePullRequest;
|
||||
import org.mian.gitnex.models.Milestones;
|
||||
import org.mian.gitnex.models.NewFile;
|
||||
@ -28,10 +33,14 @@ import org.mian.gitnex.models.OrganizationRepository;
|
||||
import org.mian.gitnex.models.Permission;
|
||||
import org.mian.gitnex.models.PullRequests;
|
||||
import org.mian.gitnex.models.Releases;
|
||||
import org.mian.gitnex.models.RepositorySettings;
|
||||
import org.mian.gitnex.models.RepositoryTransfer;
|
||||
import org.mian.gitnex.models.Status;
|
||||
import org.mian.gitnex.models.Teams;
|
||||
import org.mian.gitnex.models.UISettings;
|
||||
import org.mian.gitnex.models.UpdateIssueAssignees;
|
||||
import org.mian.gitnex.models.UpdateIssueState;
|
||||
import org.mian.gitnex.models.UserHeatmap;
|
||||
import org.mian.gitnex.models.UserInfo;
|
||||
import org.mian.gitnex.models.UserOrganizations;
|
||||
import org.mian.gitnex.models.UserRepositories;
|
||||
@ -70,8 +79,26 @@ public interface ApiInterface {
|
||||
@GET("version") // gitea version API
|
||||
Call<GiteaVersion> getGiteaVersionWithToken(@Header("Authorization") String token);
|
||||
|
||||
@GET("user") // username, full name, email
|
||||
Call<UserInfo> getUserInfo(@Header("Authorization") String token);
|
||||
@POST("markdown")
|
||||
Call<String> renderMarkdown(@Header("Authorization") String token, @Body MarkdownOption markdownOption);
|
||||
|
||||
@POST("markdown/raw")
|
||||
Call<String> renderRawMarkdown(@Header("Authorization") String token, @Body String body);
|
||||
|
||||
@GET("signing-key.gpg") // Get default signing-key.gpg
|
||||
Call<String> getSigningKey(@Header("Authorization") String token);
|
||||
|
||||
@GET("settings/api") // Get instance's global settings for api
|
||||
Call<APISettings> getAPISettings(@Header("Authorization") String token);
|
||||
|
||||
@GET("settings/attachment") // Get instance's global settings for attachments
|
||||
Call<AttachmentSettings> getAttachmentSettings(@Header("Authorization") String token);
|
||||
|
||||
@GET("settings/repository") // Get instance's global settings for repositories
|
||||
Call<RepositorySettings> getRepositorySettings(@Header("Authorization") String token);
|
||||
|
||||
@GET("settings/ui") // Get instance's global settings for ui
|
||||
Call<UISettings> getUISettings(@Header("Authorization") String token);
|
||||
|
||||
@GET("users/{username}/tokens") // get user token
|
||||
Call<List<UserTokens>> getUserTokens(@Header("Authorization") String authorization, @Path("username") String loginUid);
|
||||
@ -112,6 +139,9 @@ public interface ApiInterface {
|
||||
@PUT("repos/{owner}/{repo}/notifications") // Mark notification threads as read, pinned or unread on a specific repo
|
||||
Call<ResponseBody> markRepoNotificationThreadsAsRead(@Header("Authorization") String token, @Path("owner") String owner, @Path("repo") String repo, @Query("all") Boolean all, @Query("status-types") String[] statusTypes, @Query("to-status") String toStatus, @Query("last_read_at") String last_read_at);
|
||||
|
||||
@GET("user") // username, full name, email
|
||||
Call<UserInfo> getUserInfo(@Header("Authorization") String token);
|
||||
|
||||
@GET("user/orgs") // get user organizations
|
||||
Call<List<UserOrganizations>> getUserOrgs(@Header("Authorization") String token);
|
||||
|
||||
@ -130,6 +160,24 @@ public interface ApiInterface {
|
||||
@POST("user/repos") // create new repository
|
||||
Call<OrganizationRepository> createNewUserRepository(@Header("Authorization") String token, @Body OrganizationRepository jsonStr);
|
||||
|
||||
@GET("user/followers") // get user followers
|
||||
Call<List<UserInfo>> getFollowers(@Header("Authorization") String token);
|
||||
|
||||
@GET("user/following") // get following
|
||||
Call<List<UserInfo>> getFollowing(@Header("Authorization") String token);
|
||||
|
||||
@POST("user/emails") // add new email
|
||||
Call<JsonElement> addNewEmail(@Header("Authorization") String token, @Body AddEmail jsonStr);
|
||||
|
||||
@GET("user/emails") // get user emails
|
||||
Call<List<Emails>> getUserEmails(@Header("Authorization") String token);
|
||||
|
||||
@GET("user/starred") // get user starred repositories
|
||||
Call<List<UserRepositories>> getUserStarredRepos(@Header("Authorization") String token, @Query("page") int page, @Query("limit") int limit);
|
||||
|
||||
@GET("users/{username}/heatmap") // Get a user's heatmap
|
||||
Call<List<UserHeatmap>> getUserHeatmap(@Header("Authorization") String token, @Path("username") String username);
|
||||
|
||||
@GET("repos/{owner}/{repo}") // get repo information
|
||||
Call<UserRepositories> getUserRepository(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName);
|
||||
|
||||
@ -193,9 +241,6 @@ public interface ApiInterface {
|
||||
@PATCH("repos/{owner}/{repo}/labels/{index}") // update / patch a label
|
||||
Call<CreateLabel> patchLabel(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int labelIndex, @Body CreateLabel jsonStr);
|
||||
|
||||
@GET("user/starred") // get user starred repositories
|
||||
Call<List<UserRepositories>> getUserStarredRepos(@Header("Authorization") String token, @Query("page") int page, @Query("limit") int limit);
|
||||
|
||||
@GET("orgs/{orgName}/repos") // get repositories by org
|
||||
Call<List<UserRepositories>> getReposByOrg(@Header("Authorization") String token, @Path("orgName") String orgName, @Query("page") int page, @Query("limit") int limit);
|
||||
|
||||
@ -226,17 +271,23 @@ public interface ApiInterface {
|
||||
@PATCH("repos/{owner}/{repo}/issues/comments/{commentId}") // edit a comment
|
||||
Call<IssueComments> patchIssueComment(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("commentId") int commentId, @Body IssueComments jsonStr);
|
||||
|
||||
@GET("user/followers") // get user followers
|
||||
Call<List<UserInfo>> getFollowers(@Header("Authorization") String token);
|
||||
@GET("repos/{owner}/{repo}/issues/comments/{commentId}/reactions") // get comment reactions
|
||||
Call<List<IssueReaction>> getIssueCommentReactions(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("commentId") int commentId);
|
||||
|
||||
@GET("user/following") // get following
|
||||
Call<List<UserInfo>> getFollowing(@Header("Authorization") String token);
|
||||
@POST("repos/{owner}/{repo}/issues/comments/{commentId}/reactions") // add reaction to a comment
|
||||
Call<IssueReaction> setIssueCommentReaction(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("commentId") int commentId, @Body IssueReaction jsonStr);
|
||||
|
||||
@POST("user/emails") // add new email
|
||||
Call<JsonElement> addNewEmail(@Header("Authorization") String token, @Body AddEmail jsonStr);
|
||||
@HTTP(method = "DELETE", path = "repos/{owner}/{repo}/issues/comments/{commentId}/reactions", hasBody = true) // delete a reaction of a comment
|
||||
Call<ResponseBody> removeIssueCommentReaction(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("commentId") int commentId, @Body IssueReaction jsonStr);
|
||||
|
||||
@GET("user/emails") // get user emails
|
||||
Call<List<Emails>> getUserEmails(@Header("Authorization") String token);
|
||||
@GET("repos/{owner}/{repo}/issues/{index}/reactions") // get issue reactions
|
||||
Call<List<IssueReaction>> getIssueReactions(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int issueIndex);
|
||||
|
||||
@POST("repos/{owner}/{repo}/issues/{index}/reactions") // add reaction to an issue
|
||||
Call<IssueReaction> setIssueReaction(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int issueIndex, @Body IssueReaction jsonStr);
|
||||
|
||||
@HTTP(method = "DELETE", path = "repos/{owner}/{repo}/issues/{index}/reactions", hasBody = true) // delete a reaction of an issue
|
||||
Call<ResponseBody> removeIssueReaction(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int issueIndex, @Body IssueReaction jsonStr);
|
||||
|
||||
@GET("repos/{owner}/{repo}/issues/{index}/labels") // get issue labels
|
||||
Call<List<Labels>> getIssueLabels(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int issueIndex);
|
||||
@ -363,4 +414,12 @@ public interface ApiInterface {
|
||||
|
||||
@GET("repos/{owner}/{repo}/forks") // get all repo forks
|
||||
Call<List<UserRepositories>> getRepositoryForks(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Query("page") int page, @Query("limit") int limit);
|
||||
|
||||
@POST("repos/{owner}/{repo}/statuses/{sha}") // Create a commit status
|
||||
Call<Status> createCommitStatus(@Header("Authorization") String token, @Path("owner") String owner, @Path("repo") String repo, @Path("sha") String sha, @Body CreateStatusOption createStatusOption);
|
||||
|
||||
@GET("repos/{owner}/{repo}/statuses/{sha}") // Get a commit's statuses
|
||||
Call<List<Status>> getCommitStatuses(@Header("Authorization") String token, @Path("owner") String owner, @Path("repo") String repo, @Query("sort") String sort, @Query("state") String state, @Query("page") int page, @Query("limit") int limit);
|
||||
|
||||
|
||||
}
|
||||
|
34
app/src/main/java/org/mian/gitnex/models/APISettings.java
Normal file
34
app/src/main/java/org/mian/gitnex/models/APISettings.java
Normal file
@ -0,0 +1,34 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
/**
|
||||
* Author opyale
|
||||
*/
|
||||
|
||||
public class APISettings {
|
||||
|
||||
private int default_git_trees_per_page;
|
||||
private int default_max_blob_size;
|
||||
private int default_paging_num;
|
||||
private int max_response_items;
|
||||
|
||||
public int getDefault_git_trees_per_page() {
|
||||
|
||||
return default_git_trees_per_page;
|
||||
}
|
||||
|
||||
public int getDefault_max_blob_size() {
|
||||
|
||||
return default_max_blob_size;
|
||||
}
|
||||
|
||||
public int getDefault_paging_num() {
|
||||
|
||||
return default_paging_num;
|
||||
}
|
||||
|
||||
public int getMax_response_items() {
|
||||
|
||||
return max_response_items;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
/**
|
||||
* Author opyale
|
||||
*/
|
||||
|
||||
public class AttachmentSettings {
|
||||
|
||||
private String allowed_types;
|
||||
private boolean enabled;
|
||||
private float max_files;
|
||||
private float max_size;
|
||||
|
||||
public String getAllowed_types() {
|
||||
|
||||
return allowed_types;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public float getMax_files() {
|
||||
|
||||
return max_files;
|
||||
}
|
||||
|
||||
public float getMax_size() {
|
||||
|
||||
return max_size;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
/**
|
||||
* Author opyale
|
||||
*/
|
||||
|
||||
public class CreateStatusOption {
|
||||
|
||||
private String context;
|
||||
private String description;
|
||||
private String statusState;
|
||||
private String target_url;
|
||||
|
||||
public CreateStatusOption(String context, String description, String statusState, String target_url) {
|
||||
this.context = context;
|
||||
this.description = description;
|
||||
this.statusState = statusState;
|
||||
this.target_url = target_url;
|
||||
}
|
||||
|
||||
public String getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public String getStatusState() {
|
||||
return statusState;
|
||||
}
|
||||
|
||||
public String getTarget_url() {
|
||||
return target_url;
|
||||
}
|
||||
}
|
71
app/src/main/java/org/mian/gitnex/models/IssueReaction.java
Normal file
71
app/src/main/java/org/mian/gitnex/models/IssueReaction.java
Normal file
@ -0,0 +1,71 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Author 6543
|
||||
*/
|
||||
|
||||
public class IssueReaction {
|
||||
|
||||
private String content;
|
||||
private userObject user;
|
||||
private Date created_at;
|
||||
|
||||
public IssueReaction(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public static class userObject {
|
||||
|
||||
private int id;
|
||||
private String login;
|
||||
private String full_name;
|
||||
private String email;
|
||||
private String avatar_url;
|
||||
private String language;
|
||||
private String username;
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
public String getFull_name() {
|
||||
return full_name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getAvatar_url() {
|
||||
return avatar_url;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public userObject getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public Date getCreated_at() {
|
||||
return created_at;
|
||||
}
|
||||
|
||||
}
|
42
app/src/main/java/org/mian/gitnex/models/MarkdownOption.java
Normal file
42
app/src/main/java/org/mian/gitnex/models/MarkdownOption.java
Normal file
@ -0,0 +1,42 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
/**
|
||||
* Author opyale
|
||||
*/
|
||||
|
||||
public class MarkdownOption {
|
||||
|
||||
private String Context;
|
||||
private String Mode;
|
||||
private String Text;
|
||||
private boolean Wiki;
|
||||
|
||||
public MarkdownOption(String context, String mode, String text, boolean wiki) {
|
||||
|
||||
Context = context;
|
||||
Mode = mode;
|
||||
Text = text;
|
||||
Wiki = wiki;
|
||||
}
|
||||
|
||||
public String getContext() {
|
||||
|
||||
return Context;
|
||||
}
|
||||
|
||||
public String getMode() {
|
||||
|
||||
return Mode;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
|
||||
return Text;
|
||||
}
|
||||
|
||||
public boolean isWiki() {
|
||||
|
||||
return Wiki;
|
||||
}
|
||||
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
/**
|
||||
* Author com.github.abumoallim, modified by M M Arif
|
||||
*/
|
||||
|
||||
public class MultiSelectModel {
|
||||
|
||||
private Integer id;
|
||||
private String name;
|
||||
private Boolean isSelected;
|
||||
|
||||
public MultiSelectModel(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Boolean getSelected() {
|
||||
return isSelected;
|
||||
}
|
||||
|
||||
public void setSelected(Boolean selected) {
|
||||
isSelected = selected;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
/**
|
||||
* Author opyale
|
||||
*/
|
||||
|
||||
public class RepositorySettings {
|
||||
|
||||
private boolean http_git_disabled;
|
||||
private boolean mirrors_disabled;
|
||||
|
||||
public boolean isHttp_git_disabled() {
|
||||
|
||||
return http_git_disabled;
|
||||
}
|
||||
|
||||
public boolean isMirrors_disabled() {
|
||||
|
||||
return mirrors_disabled;
|
||||
}
|
||||
|
||||
}
|
56
app/src/main/java/org/mian/gitnex/models/Status.java
Normal file
56
app/src/main/java/org/mian/gitnex/models/Status.java
Normal file
@ -0,0 +1,56 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Author opyale
|
||||
*/
|
||||
|
||||
public class Status {
|
||||
|
||||
private String context;
|
||||
private Date created_at;
|
||||
private UserInfo creator;
|
||||
private String description;
|
||||
private int id;
|
||||
private String status;
|
||||
private String target_url;
|
||||
private Date updated_at;
|
||||
private String url;
|
||||
|
||||
public String getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public Date getCreated_at() {
|
||||
return created_at;
|
||||
}
|
||||
|
||||
public UserInfo getCreator() {
|
||||
return creator;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public String getTarget_url() {
|
||||
return target_url;
|
||||
}
|
||||
|
||||
public Date getUpdated_at() {
|
||||
return updated_at;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
}
|
16
app/src/main/java/org/mian/gitnex/models/UISettings.java
Normal file
16
app/src/main/java/org/mian/gitnex/models/UISettings.java
Normal file
@ -0,0 +1,16 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
/**
|
||||
* Author opyale
|
||||
*/
|
||||
|
||||
public class UISettings {
|
||||
|
||||
private String[] allowed_reactions;
|
||||
|
||||
public String[] getAllowed_reactions() {
|
||||
|
||||
return allowed_reactions;
|
||||
}
|
||||
|
||||
}
|
12
app/src/main/java/org/mian/gitnex/models/UserHeatmap.java
Normal file
12
app/src/main/java/org/mian/gitnex/models/UserHeatmap.java
Normal file
@ -0,0 +1,12 @@
|
||||
package org.mian.gitnex.models;
|
||||
|
||||
/**
|
||||
* Author opyale
|
||||
*/
|
||||
|
||||
public class UserHeatmap {
|
||||
|
||||
private long contributions;
|
||||
private long timestamp;
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package org.mian.gitnex.helpers;
|
||||
package org.mian.gitnex.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
140
app/src/main/java/org/mian/gitnex/views/ReactionList.java
Normal file
140
app/src/main/java/org/mian/gitnex/views/ReactionList.java
Normal file
@ -0,0 +1,140 @@
|
||||
package org.mian.gitnex.views;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import com.vdurmont.emoji.Emoji;
|
||||
import com.vdurmont.emoji.EmojiManager;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.clients.RetrofitClient;
|
||||
import org.mian.gitnex.helpers.AppUtil;
|
||||
import org.mian.gitnex.helpers.Authorization;
|
||||
import org.mian.gitnex.helpers.TinyDB;
|
||||
import org.mian.gitnex.models.IssueReaction;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import retrofit2.Response;
|
||||
|
||||
/**
|
||||
* @author opyale
|
||||
*/
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class ReactionList extends HorizontalScrollView {
|
||||
|
||||
private enum ReactionType { COMMENT, ISSUE }
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
public ReactionList(Context context, Bundle bundle) {
|
||||
|
||||
super(context);
|
||||
|
||||
LinearLayout root = new LinearLayout(context);
|
||||
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
root.setOrientation(LinearLayout.HORIZONTAL);
|
||||
root.setGravity(Gravity.START);
|
||||
root.setLayoutParams(layoutParams);
|
||||
|
||||
addView(root);
|
||||
setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
TinyDB tinyDB = TinyDB.getInstance(context);
|
||||
|
||||
String loginUid = tinyDB.getString("loginUid");
|
||||
String repoOwner = bundle.getString("repoOwner");
|
||||
String repoName = bundle.getString("repoName");
|
||||
|
||||
int id;
|
||||
ReactionType reactionType;
|
||||
|
||||
if(bundle.containsKey("commentId")) {
|
||||
id = bundle.getInt("commentId");
|
||||
reactionType = ReactionType.COMMENT;
|
||||
} else {
|
||||
id = bundle.getInt("issueId");
|
||||
reactionType = ReactionType.ISSUE;
|
||||
}
|
||||
|
||||
new Thread(() -> {
|
||||
|
||||
try {
|
||||
|
||||
Response<List<IssueReaction>> response = null;
|
||||
|
||||
switch(reactionType) {
|
||||
|
||||
case ISSUE:
|
||||
response = RetrofitClient
|
||||
.getApiInterface(context)
|
||||
.getIssueReactions(Authorization.get(context), repoOwner, repoName, id)
|
||||
.execute();
|
||||
break;
|
||||
|
||||
case COMMENT:
|
||||
response = RetrofitClient
|
||||
.getApiInterface(context)
|
||||
.getIssueCommentReactions(Authorization.get(context), repoOwner, repoName, id)
|
||||
.execute();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
Map<String, List<IssueReaction>> sortedReactions = new HashMap<>();
|
||||
|
||||
if(response.isSuccessful() && response.body() != null) {
|
||||
|
||||
for(IssueReaction issueReaction : response.body()) {
|
||||
|
||||
if(sortedReactions.containsKey(issueReaction.getContent())) {
|
||||
|
||||
sortedReactions.get(issueReaction.getContent()).add(issueReaction);
|
||||
} else {
|
||||
List<IssueReaction> issueReactions = new ArrayList<>();
|
||||
issueReactions.add(issueReaction);
|
||||
|
||||
sortedReactions.put(issueReaction.getContent(), issueReactions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(String content : sortedReactions.keySet()) {
|
||||
|
||||
List<IssueReaction> issueReactions = sortedReactions.get(content);
|
||||
|
||||
@SuppressLint("InflateParams") CardView reactionBadge = (CardView) LayoutInflater.from(context)
|
||||
.inflate(R.layout.layout_reaction_badge, this, false);
|
||||
|
||||
for(IssueReaction issueReaction : issueReactions) {
|
||||
|
||||
if(issueReaction.getUser().getLogin().equals(loginUid)) {
|
||||
reactionBadge.setCardBackgroundColor(AppUtil.getColorFromAttribute(context, R.attr.inputSelectedColor));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Emoji emoji = EmojiManager.getForAlias(content);
|
||||
|
||||
((TextView) reactionBadge.findViewById(R.id.symbol)).setText(((emoji == null) ? content : emoji.getUnicode()) + " " + issueReactions.size());
|
||||
root.post(() -> root.addView(reactionBadge));
|
||||
|
||||
}
|
||||
|
||||
} catch (IOException ignored) {}
|
||||
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
}
|
238
app/src/main/java/org/mian/gitnex/views/ReactionSpinner.java
Normal file
238
app/src/main/java/org/mian/gitnex/views/ReactionSpinner.java
Normal file
@ -0,0 +1,238 @@
|
||||
package org.mian.gitnex.views;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import com.vdurmont.emoji.Emoji;
|
||||
import com.vdurmont.emoji.EmojiManager;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.clients.RetrofitClient;
|
||||
import org.mian.gitnex.helpers.AppUtil;
|
||||
import org.mian.gitnex.helpers.Authorization;
|
||||
import org.mian.gitnex.helpers.TinyDB;
|
||||
import org.mian.gitnex.models.IssueReaction;
|
||||
import org.mian.gitnex.models.UISettings;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import retrofit2.Response;
|
||||
|
||||
/**
|
||||
* @author opyale
|
||||
*/
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class ReactionSpinner extends HorizontalScrollView {
|
||||
|
||||
private enum ReactionType { COMMENT, ISSUE }
|
||||
private enum ReactionAction { REMOVE, ADD }
|
||||
|
||||
private OnInteractedListener onInteractedListener;
|
||||
|
||||
public ReactionSpinner(Context context, Bundle bundle) {
|
||||
|
||||
super(context);
|
||||
|
||||
LinearLayout root = new LinearLayout(context);
|
||||
|
||||
int dens = AppUtil.getPixelsFromDensity(context, 10);
|
||||
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
root.setOrientation(LinearLayout.HORIZONTAL);
|
||||
root.setPadding(dens, 0, dens, 0);
|
||||
root.setGravity(Gravity.START);
|
||||
root.setLayoutParams(layoutParams);
|
||||
|
||||
TinyDB tinyDB = TinyDB.getInstance(context);
|
||||
|
||||
String loginUid = tinyDB.getString("loginUid");
|
||||
String repoOwner = bundle.getString("repoOwner");
|
||||
String repoName = bundle.getString("repoName");
|
||||
|
||||
int id;
|
||||
ReactionType reactionType;
|
||||
|
||||
if(bundle.containsKey("commentId")) {
|
||||
id = bundle.getInt("commentId");
|
||||
reactionType = ReactionType.COMMENT;
|
||||
} else {
|
||||
id = bundle.getInt("issueId");
|
||||
reactionType = ReactionType.ISSUE;
|
||||
}
|
||||
|
||||
new Thread(() -> {
|
||||
|
||||
try {
|
||||
|
||||
List<IssueReaction> allReactions = getReactions(repoOwner, repoName, reactionType, id);
|
||||
|
||||
for(String allowedReaction : getAllowedReactions()) {
|
||||
|
||||
@SuppressLint("InflateParams") CardView reactionButton = (CardView) LayoutInflater.from(context)
|
||||
.inflate(R.layout.layout_reaction_button, root, false);
|
||||
|
||||
IssueReaction myReaction = null;
|
||||
|
||||
for(IssueReaction issueReaction : allReactions) {
|
||||
|
||||
if(issueReaction.getContent().equals(allowedReaction) && issueReaction.getUser().getLogin().equals(loginUid)) {
|
||||
myReaction = issueReaction;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ReactionAction reactionAction;
|
||||
|
||||
if(myReaction != null) {
|
||||
|
||||
reactionButton.setCardBackgroundColor(AppUtil.getColorFromAttribute(context, R.attr.inputSelectedColor));
|
||||
reactionAction = ReactionAction.REMOVE;
|
||||
} else {
|
||||
reactionAction = ReactionAction.ADD;
|
||||
}
|
||||
|
||||
reactionButton.setOnClickListener(v -> new Thread(() -> {
|
||||
|
||||
try {
|
||||
if(react(repoOwner, repoName, reactionType, reactionAction, new IssueReaction(allowedReaction), id)) {
|
||||
v.post(() -> onInteractedListener.onInteracted());
|
||||
}
|
||||
} catch(IOException ignored) {}
|
||||
|
||||
}).start());
|
||||
|
||||
Emoji emoji = EmojiManager.getForAlias(allowedReaction);
|
||||
|
||||
((TextView) reactionButton.findViewById(R.id.symbol)).setText((emoji == null) ? allowedReaction : emoji.getUnicode());
|
||||
root.post(() -> root.addView(reactionButton));
|
||||
|
||||
}
|
||||
|
||||
} catch(IOException ignored) {}
|
||||
|
||||
}).start();
|
||||
|
||||
setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
addView(root);
|
||||
|
||||
}
|
||||
|
||||
private boolean react(String repoOwner, String repoName, ReactionType reactionType, ReactionAction reactionAction, IssueReaction issueReaction, int id) throws IOException {
|
||||
|
||||
Response<?> response = null;
|
||||
|
||||
switch(reactionType) {
|
||||
|
||||
case ISSUE:
|
||||
switch(reactionAction) {
|
||||
|
||||
case ADD:
|
||||
response = RetrofitClient
|
||||
.getApiInterface(getContext())
|
||||
.setIssueReaction(Authorization.get(getContext()), repoOwner, repoName, id, issueReaction)
|
||||
.execute();
|
||||
break;
|
||||
|
||||
|
||||
case REMOVE:
|
||||
response = RetrofitClient
|
||||
.getApiInterface(getContext())
|
||||
.removeIssueReaction(Authorization.get(getContext()), repoOwner, repoName, id, issueReaction)
|
||||
.execute();
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMENT:
|
||||
switch(reactionAction) {
|
||||
|
||||
case ADD:
|
||||
response = RetrofitClient
|
||||
.getApiInterface(getContext())
|
||||
.setIssueCommentReaction(Authorization.get(getContext()), repoOwner, repoName, id, issueReaction)
|
||||
.execute();
|
||||
break;
|
||||
|
||||
|
||||
case REMOVE:
|
||||
response = RetrofitClient
|
||||
.getApiInterface(getContext())
|
||||
.removeIssueCommentReaction(Authorization.get(getContext()), repoOwner, repoName, id, issueReaction)
|
||||
.execute();
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return response.isSuccessful();
|
||||
|
||||
}
|
||||
|
||||
private List<IssueReaction> getReactions(String repoOwner, String repoName, ReactionType reactionType, int id) throws IOException {
|
||||
|
||||
Response<List<IssueReaction>> response = null;
|
||||
|
||||
switch(reactionType) {
|
||||
|
||||
case ISSUE:
|
||||
response = RetrofitClient
|
||||
.getApiInterface(getContext())
|
||||
.getIssueReactions(Authorization.get(getContext()), repoOwner, repoName, id)
|
||||
.execute();
|
||||
break;
|
||||
|
||||
case COMMENT:
|
||||
response = RetrofitClient
|
||||
.getApiInterface(getContext())
|
||||
.getIssueCommentReactions(Authorization.get(getContext()), repoOwner, repoName, id)
|
||||
.execute();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if(response.isSuccessful() && response.body() != null)
|
||||
return response.body();
|
||||
else
|
||||
return Collections.emptyList();
|
||||
|
||||
}
|
||||
|
||||
private List<String> getAllowedReactions() throws IOException {
|
||||
|
||||
List<String> allowedReactions = new ArrayList<>();
|
||||
|
||||
Response<UISettings> response = RetrofitClient
|
||||
.getApiInterface(getContext())
|
||||
.getUISettings(Authorization.get(getContext()))
|
||||
.execute();
|
||||
|
||||
if(response.isSuccessful() && response.body() != null) {
|
||||
allowedReactions.addAll(Arrays.asList(response.body().getAllowed_reactions()));
|
||||
} else {
|
||||
allowedReactions.addAll(Arrays.asList("+1", "-1", "laugh", "hooray", "confused", "heart", "rocket", "eyes"));
|
||||
}
|
||||
|
||||
return allowedReactions;
|
||||
|
||||
}
|
||||
|
||||
public void setOnInteractedListener(OnInteractedListener onInteractedListener) {
|
||||
this.onInteractedListener = onInteractedListener;
|
||||
}
|
||||
|
||||
public interface OnInteractedListener { void onInteracted(); }
|
||||
|
||||
}
|
@ -225,6 +225,14 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/commentReactionBadges"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/issueTimeFrame"
|
||||
android:layout_marginTop="10dp"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<View
|
||||
|
@ -4,10 +4,10 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/primaryBackgroundColor"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:background="?attr/primaryBackgroundColor">
|
||||
android:paddingBottom="12dp">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
@ -15,8 +15,15 @@
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/commentReactionButtons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/commentMenuEdit"
|
||||
|
@ -17,6 +17,13 @@
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/commentReactionButtons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/openFilesDiff"
|
||||
android:layout_width="match_parent"
|
||||
|
24
app/src/main/res/layout/layout_reaction_badge.xml
Normal file
24
app/src/main/res/layout/layout_reaction_badge.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
app:cardBackgroundColor="?attr/inputBackgroundColor"
|
||||
app:cardCornerRadius="10dp"
|
||||
app:cardElevation="0dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/symbol"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingBottom="3dp"
|
||||
android:textColor="?attr/primaryTextColor"
|
||||
android:textSize="15sp"
|
||||
tools:text="👍" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
22
app/src/main/res/layout/layout_reaction_button.xml
Normal file
22
app/src/main/res/layout/layout_reaction_button.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp"
|
||||
app:cardBackgroundColor="?attr/inputBackgroundColor"
|
||||
app:cardCornerRadius="25sp"
|
||||
app:cardElevation="0dp"
|
||||
app:contentPadding="10dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/symbol"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:textColor="?attr/primaryTextColor"
|
||||
android:textSize="20sp"
|
||||
tools:text="👍" />
|
||||
|
||||
</androidx.cardview.widget.CardView>
|
@ -71,4 +71,11 @@
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/commentReactionBadges"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="15dp"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
</LinearLayout>
|
||||
|
@ -17,6 +17,7 @@
|
||||
<item name="primaryTextColor">@color/lightThemeTextColor</item>
|
||||
<item name="primaryBackgroundColor">@color/lightThemeBackground</item>
|
||||
<item name="inputBackgroundColor">@color/lightThemeInputBackground</item>
|
||||
<item name="inputSelectedColor">@color/lightThemInputSelected</item>
|
||||
<item name="inputTextColor">@color/lightThemeInputTextColor</item>
|
||||
<item name="checkboxStyle">@style/AppThemeLightCheckBoxStyle</item>
|
||||
<item name="selectedTextColor">@color/darkGreen</item>
|
||||
@ -57,6 +58,7 @@
|
||||
<item name="primaryTextColor">@color/retroThemeTextColor</item>
|
||||
<item name="primaryBackgroundColor">@color/retroThemeBackground</item>
|
||||
<item name="inputBackgroundColor">@color/retroThemeInputBackground</item>
|
||||
<item name="inputSelectedColor">@color/retroThemeInputSelected</item>
|
||||
<item name="inputTextColor">@color/retroThemeInputTextColor</item>
|
||||
<item name="checkboxStyle">@style/AppThemeRetroCheckBoxStyle</item>
|
||||
<item name="selectedTextColor">@color/retroThemeColorPrimary</item>
|
||||
|
@ -6,6 +6,7 @@
|
||||
<attr name="primaryTextColor" format="reference"/>
|
||||
<attr name="primaryBackgroundColor" format="reference" />
|
||||
<attr name="inputBackgroundColor" format="reference" />
|
||||
<attr name="inputSelectedColor" format="reference" />
|
||||
<attr name="hintColor" format="reference" />
|
||||
<attr name="inputTextColor" format="reference" />
|
||||
<attr name="selectedTextColor" format="reference" />
|
||||
|
@ -12,6 +12,7 @@
|
||||
<color name="btnBackground">#009486</color>
|
||||
<color name="btnTextColor">#ffffff</color>
|
||||
<color name="inputBackground">#1d1d1d</color>
|
||||
<color name="inputSelected">#3A3A3A</color>
|
||||
<color name="toastBackground">#1d1d1d</color>
|
||||
<color name="releasePre">#f2711c</color>
|
||||
<color name="releaseStable">@color/btnBackground</color>
|
||||
@ -35,7 +36,8 @@
|
||||
<color name="lightThemeDiffSelectedColor">#e0e0e0</color>
|
||||
<color name="lightThemeTextColor">#646565</color>
|
||||
<color name="lightThemeBackground">#f9f9f9</color>
|
||||
<color name="lightThemeInputBackground">#f2f2f2</color>
|
||||
<color name="lightThemeInputBackground">#EFEFEF</color>
|
||||
<color name="lightThemInputSelected">#C9CCCC</color>
|
||||
<color name="lightThemeInputTextColor">#212121</color>
|
||||
<color name="lightThemeDividerColor">#dbdbdb</color>
|
||||
|
||||
@ -45,6 +47,7 @@
|
||||
<color name="retroThemeTextColor">#212f3c</color>
|
||||
<color name="retroThemeBackground">#fcfcfc</color>
|
||||
<color name="retroThemeInputBackground">#f2f2f2</color>
|
||||
<color name="retroThemeInputSelected">#D3D3D3</color>
|
||||
<color name="retroThemeInputTextColor">#6200EE</color>
|
||||
<color name="retroThemeDividerColor">#dbdbdb</color>
|
||||
<color name="retroThemeColorPrimary">#6200EE</color>
|
||||
|
@ -17,6 +17,7 @@
|
||||
<item name="primaryTextColor">@color/colorWhite</item>
|
||||
<item name="primaryBackgroundColor">@color/colorPrimary</item>
|
||||
<item name="inputBackgroundColor">@color/inputBackground</item>
|
||||
<item name="inputSelectedColor">@color/inputSelected</item>
|
||||
<item name="inputTextColor">@color/colorWhite</item>
|
||||
<item name="checkboxStyle">@style/AppThemeCheckBoxStyle</item>
|
||||
<item name="selectedTextColor">@color/darkGreen</item>
|
||||
@ -56,6 +57,7 @@
|
||||
<item name="primaryTextColor">@color/lightThemeTextColor</item>
|
||||
<item name="primaryBackgroundColor">@color/lightThemeBackground</item>
|
||||
<item name="inputBackgroundColor">@color/lightThemeInputBackground</item>
|
||||
<item name="inputSelectedColor">@color/lightThemInputSelected</item>
|
||||
<item name="inputTextColor">@color/lightThemeInputTextColor</item>
|
||||
<item name="checkboxStyle">@style/AppThemeLightCheckBoxStyle</item>
|
||||
<item name="selectedTextColor">@color/darkGreen</item>
|
||||
@ -95,6 +97,7 @@
|
||||
<item name="primaryTextColor">@color/retroThemeTextColor</item>
|
||||
<item name="primaryBackgroundColor">@color/retroThemeBackground</item>
|
||||
<item name="inputBackgroundColor">@color/retroThemeInputBackground</item>
|
||||
<item name="inputSelectedColor">@color/retroThemeInputSelected</item>
|
||||
<item name="inputTextColor">@color/retroThemeInputTextColor</item>
|
||||
<item name="checkboxStyle">@style/AppThemeRetroCheckBoxStyle</item>
|
||||
<item name="selectedTextColor">@color/retroThemeColorPrimary</item>
|
||||
|
Loading…
Reference in New Issue
Block a user