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:
opyale 2020-11-08 19:58:47 +01:00 committed by M M Arif
parent f97f668363
commit ade7b797f1
33 changed files with 1000 additions and 101 deletions

View File

@ -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>

View File

@ -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)

View File

@ -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'
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);

View File

@ -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("-");

View File

@ -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();
}

View File

@ -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);
}

View 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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View 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;
}
}

View 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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View 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;
}
}

View 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;
}
}

View File

@ -0,0 +1,12 @@
package org.mian.gitnex.models;
/**
* Author opyale
*/
public class UserHeatmap {
private long contributions;
private long timestamp;
}

View File

@ -1,4 +1,4 @@
package org.mian.gitnex.helpers;
package org.mian.gitnex.views;
import android.content.Context;
import android.util.AttributeSet;

View 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();
}
}

View 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(); }
}

View File

@ -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

View File

@ -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"

View File

@ -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"

View 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>

View 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>

View File

@ -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>

View File

@ -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>

View File

@ -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" />

View File

@ -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>

View File

@ -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>