From d2728716b8169712ee9570b4b2f5cccd9d4129bf Mon Sep 17 00:00:00 2001 From: nuclearfog Date: Tue, 10 Oct 2023 22:22:09 +0200 Subject: [PATCH] added report rule selector, added report dialog to profile --- .../twidda/backend/api/Connection.java | 6 + .../twidda/backend/api/mastodon/Mastodon.java | 31 ++++- .../api/mastodon/impl/MastodonRule.java | 61 +++++++++ .../twidda/backend/async/RuleLoader.java | 38 ++++++ .../backend/helper/update/ReportUpdate.java | 6 +- .../org/nuclearfog/twidda/model/Rule.java | 19 +++ .../nuclearfog/twidda/model/lists/Rules.java | 26 ++++ .../twidda/ui/activities/ProfileActivity.java | 20 ++- .../ui/adapter/listview/RuleAdapter.java | 126 ++++++++++++++++++ .../twidda/ui/dialogs/ReportDialog.java | 75 ++++++++--- app/src/main/res/layout/dialog_report.xml | 13 +- app/src/main/res/layout/item_option.xml | 17 +-- app/src/main/res/layout/item_rule.xml | 23 ++++ app/src/main/res/menu/profile.xml | 5 + app/src/main/res/values/dimens.xml | 5 +- 15 files changed, 425 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/org/nuclearfog/twidda/backend/api/mastodon/impl/MastodonRule.java create mode 100644 app/src/main/java/org/nuclearfog/twidda/backend/async/RuleLoader.java create mode 100644 app/src/main/java/org/nuclearfog/twidda/model/Rule.java create mode 100644 app/src/main/java/org/nuclearfog/twidda/model/lists/Rules.java create mode 100644 app/src/main/java/org/nuclearfog/twidda/ui/adapter/listview/RuleAdapter.java create mode 100644 app/src/main/res/layout/item_rule.xml diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/api/Connection.java b/app/src/main/java/org/nuclearfog/twidda/backend/api/Connection.java index 7a3ba33a..98ed3edc 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/api/Connection.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/api/Connection.java @@ -30,6 +30,7 @@ import org.nuclearfog.twidda.model.lists.Domains; import org.nuclearfog.twidda.model.lists.Filters; import org.nuclearfog.twidda.model.lists.Hashtags; import org.nuclearfog.twidda.model.lists.Notifications; +import org.nuclearfog.twidda.model.lists.Rules; import org.nuclearfog.twidda.model.lists.ScheduledStatuses; import org.nuclearfog.twidda.model.lists.Statuses; import org.nuclearfog.twidda.model.lists.UserLists; @@ -711,4 +712,9 @@ public interface Connection { * @param update report contianing information about status/user */ void createReport(ReportUpdate update) throws ConnectionException; + + /** + * get rules of an instance + */ + Rules getRules() throws ConnectionException; } \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/api/mastodon/Mastodon.java b/app/src/main/java/org/nuclearfog/twidda/backend/api/mastodon/Mastodon.java index 2fffc79e..8372d5b7 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/api/mastodon/Mastodon.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/api/mastodon/Mastodon.java @@ -25,6 +25,7 @@ import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonNotification; import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonPoll; import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonPush; import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonRelation; +import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonRule; import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonStatus; import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonTranslation; import org.nuclearfog.twidda.backend.api.mastodon.impl.MastodonUser; @@ -61,6 +62,7 @@ import org.nuclearfog.twidda.model.lists.Domains; import org.nuclearfog.twidda.model.lists.Filters; import org.nuclearfog.twidda.model.lists.Hashtags; import org.nuclearfog.twidda.model.lists.Notifications; +import org.nuclearfog.twidda.model.lists.Rules; import org.nuclearfog.twidda.model.lists.ScheduledStatuses; import org.nuclearfog.twidda.model.lists.Statuses; import org.nuclearfog.twidda.model.lists.UserLists; @@ -154,6 +156,7 @@ public class Mastodon implements Connection { private static final String ENDPOINT_FILTER = "/api/v2/filters"; private static final String ENDPOINT_REPORT = "/api/v1/reports"; private static final String ENDPOINT_SCHEDULED_STATUS = "/api/v1/scheduled_statuses"; + private static final String ENDPOINT_GET_RULES = "/api/v1/instance/rules"; private static final MediaType TYPE_TEXT = MediaType.parse("text/plain"); private static final MediaType TYPE_STREAM = MediaType.parse("application/octet-stream"); @@ -1340,7 +1343,7 @@ public class Mastodon implements Connection { params.add("account_id=" + update.getUserId()); for (long statusId : update.getStatusIds()) params.add("status_ids[]=" + statusId); - for (int ruleId : update.getRuleIds()) + for (long ruleId : update.getRuleIds()) params.add("rule_ids[]=" + ruleId); if (!update.getComment().trim().isEmpty()) params.add("comment=" + StringUtils.encode(update.getComment())); @@ -1361,6 +1364,32 @@ public class Mastodon implements Connection { } } + + @Override + public Rules getRules() throws ConnectionException { + try { + Response response = get(ENDPOINT_GET_RULES, new ArrayList<>()); + ResponseBody body = response.body(); + if (response.code() == 200 && body != null) { + JSONArray jsonArray = new JSONArray(body.string()); + Rules rules = new Rules(jsonArray.length()); + for (int i = 0; i < jsonArray.length(); i++) { + try { + rules.add(new MastodonRule(jsonArray.getJSONObject(i))); + } catch (JSONException e) { + if (BuildConfig.DEBUG) { + e.printStackTrace(); + } + } + } + return rules; + } + throw new MastodonException(response); + } catch (IOException | JSONException e) { + throw new MastodonException(e); + } + } + /** * get information about the current user * diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/api/mastodon/impl/MastodonRule.java b/app/src/main/java/org/nuclearfog/twidda/backend/api/mastodon/impl/MastodonRule.java new file mode 100644 index 00000000..8f22ae0d --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/backend/api/mastodon/impl/MastodonRule.java @@ -0,0 +1,61 @@ +package org.nuclearfog.twidda.backend.api.mastodon.impl; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.json.JSONException; +import org.json.JSONObject; +import org.nuclearfog.twidda.model.Rule; + +/** + * Mastodon implementation of a {@link Rule} + * + * @author nuclearfog + */ +public class MastodonRule implements Rule { + + private static final long serialVersionUID = 735539108133555221L; + + private long id; + private String description; + + /** + * + */ + public MastodonRule(JSONObject json) throws JSONException { + String idStr = json.getString("id"); + description = json.getString("text"); + try { + id = Long.parseLong(idStr); + } catch (NumberFormatException exception) { + throw new JSONException("bad ID: " + idStr); + } + } + + + @Override + public long getId() { + return id; + } + + + @Override + public String getDescription() { + return description; + } + + + @Override + public boolean equals(@Nullable Object obj) { + if (!(obj instanceof Rule)) + return false; + return ((Rule) obj).getId() == getId(); + } + + + @NonNull + @Override + public String toString() { + return "id=" + getId() + " description=\"" + getDescription() + "\""; + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/async/RuleLoader.java b/app/src/main/java/org/nuclearfog/twidda/backend/async/RuleLoader.java new file mode 100644 index 00000000..a33b942e --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/backend/async/RuleLoader.java @@ -0,0 +1,38 @@ +package org.nuclearfog.twidda.backend.async; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import org.nuclearfog.twidda.backend.api.Connection; +import org.nuclearfog.twidda.backend.api.ConnectionException; +import org.nuclearfog.twidda.backend.api.ConnectionManager; +import org.nuclearfog.twidda.model.lists.Rules; + +/** + * Loader class used to load instance rules + * + * @author nuclearfog + * @see org.nuclearfog.twidda.ui.dialogs.ReportDialog + */ +public class RuleLoader extends AsyncExecutor { + + private Connection connection; + + /** + * + */ + public RuleLoader(Context context) { + connection = ConnectionManager.getDefaultConnection(context); + } + + + @Override + protected Rules doInBackground(@NonNull Void param) { + try { + return connection.getRules(); + } catch (ConnectionException exception) { + return null; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/backend/helper/update/ReportUpdate.java b/app/src/main/java/org/nuclearfog/twidda/backend/helper/update/ReportUpdate.java index cb57c19c..e93958e6 100644 --- a/app/src/main/java/org/nuclearfog/twidda/backend/helper/update/ReportUpdate.java +++ b/app/src/main/java/org/nuclearfog/twidda/backend/helper/update/ReportUpdate.java @@ -20,7 +20,7 @@ public class ReportUpdate implements Serializable { private long userId; private long[] statusIds = {}; - private int[] ruleIds = {}; + private long[] ruleIds = {}; private String comment = ""; private int category = CATEGORY_OTHER; private boolean forward = false; @@ -64,7 +64,7 @@ public class ReportUpdate implements Serializable { * * @param ruleIds array of rule IDs */ - public void setRuleIds(int[] ruleIds) { + public void setRuleIds(long[] ruleIds) { this.ruleIds = Arrays.copyOf(ruleIds, ruleIds.length); } @@ -73,7 +73,7 @@ public class ReportUpdate implements Serializable { * * @return array of rule IDs */ - public int[] getRuleIds() { + public long[] getRuleIds() { return Arrays.copyOf(ruleIds, ruleIds.length); } diff --git a/app/src/main/java/org/nuclearfog/twidda/model/Rule.java b/app/src/main/java/org/nuclearfog/twidda/model/Rule.java new file mode 100644 index 00000000..1cf1984c --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/model/Rule.java @@ -0,0 +1,19 @@ +package org.nuclearfog.twidda.model; + +import java.io.Serializable; + +/** + * Represents a rule of an {@link Instance} + */ +public interface Rule extends Serializable { + + /** + * get ID of the rule + */ + long getId(); + + /** + * get detailed description of this rule + */ + String getDescription(); +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/model/lists/Rules.java b/app/src/main/java/org/nuclearfog/twidda/model/lists/Rules.java new file mode 100644 index 00000000..60025035 --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/model/lists/Rules.java @@ -0,0 +1,26 @@ +package org.nuclearfog.twidda.model.lists; + +import org.nuclearfog.twidda.model.Rule; + +import java.util.ArrayList; + +/** + * @author nuclearfog + */ +public class Rules extends ArrayList { + + private static final long serialVersionUID = -8984532893479237315L; + + /** + * + */ + public Rules() { + } + + /** + * + */ + public Rules(int cap) { + super(cap); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/ui/activities/ProfileActivity.java b/app/src/main/java/org/nuclearfog/twidda/ui/activities/ProfileActivity.java index b677a83b..2f1da47e 100644 --- a/app/src/main/java/org/nuclearfog/twidda/ui/activities/ProfileActivity.java +++ b/app/src/main/java/org/nuclearfog/twidda/ui/activities/ProfileActivity.java @@ -54,6 +54,7 @@ import org.nuclearfog.twidda.model.User; import org.nuclearfog.twidda.ui.adapter.viewpager.ProfileAdapter; import org.nuclearfog.twidda.ui.dialogs.ConfirmDialog; import org.nuclearfog.twidda.ui.dialogs.ConfirmDialog.OnConfirmListener; +import org.nuclearfog.twidda.ui.dialogs.ReportDialog; import org.nuclearfog.twidda.ui.views.LockableConstraintLayout; import org.nuclearfog.twidda.ui.views.TabSelector; import org.nuclearfog.twidda.ui.views.TabSelector.OnTabSelectedListener; @@ -118,6 +119,7 @@ public class ProfileActivity extends AppCompatActivity implements OnClickListene private GlobalSettings settings; private Picasso picasso; private ConfirmDialog confirmDialog; + private ReportDialog reportDialog; private DomainAction domainAction; private RelationLoader relationLoader; @@ -173,6 +175,7 @@ public class ProfileActivity extends AppCompatActivity implements OnClickListene userLoader = new UserLoader(this); emojiLoader = new TextEmojiLoader(this); confirmDialog = new ConfirmDialog(this, this); + reportDialog = new ReportDialog(this); picasso = PicassoBuilder.get(this); settings = GlobalSettings.get(this); adapter = new ProfileAdapter(this); @@ -289,15 +292,14 @@ public class ProfileActivity extends AppCompatActivity implements OnClickListene boolean result = super.onPrepareOptionsMenu(m); if (user != null) { MenuItem listItem = m.findItem(R.id.profile_lists); - MenuItem domainBlock = m.findItem(R.id.profile_block_domain); + MenuItem domainItem = m.findItem(R.id.profile_block_domain); + MenuItem reportItem = m.findItem(R.id.profile_report); switch (settings.getLogin().getConfiguration()) { case MASTODON: - if (user.isCurrentUser()) { - listItem.setVisible(true); - } else { - domainBlock.setVisible(true); - } + listItem.setVisible(user.isCurrentUser()); + domainItem.setVisible(!user.isCurrentUser()); + reportItem .setVisible(!user.isCurrentUser()); break; } if (user.followRequested()) { @@ -408,6 +410,12 @@ public class ProfileActivity extends AppCompatActivity implements OnClickListene confirmDialog.show(ConfirmDialog.DOMAIN_BLOCK_ADD); } } + // report user + else if (item.getItemId() == R.id.profile_report) { + if (user != null) { + reportDialog.show(user.getId()); + } + } return super.onOptionsItemSelected(item); } diff --git a/app/src/main/java/org/nuclearfog/twidda/ui/adapter/listview/RuleAdapter.java b/app/src/main/java/org/nuclearfog/twidda/ui/adapter/listview/RuleAdapter.java new file mode 100644 index 00000000..923931e0 --- /dev/null +++ b/app/src/main/java/org/nuclearfog/twidda/ui/adapter/listview/RuleAdapter.java @@ -0,0 +1,126 @@ +package org.nuclearfog.twidda.ui.adapter.listview; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import org.nuclearfog.twidda.R; +import org.nuclearfog.twidda.config.GlobalSettings; +import org.nuclearfog.twidda.model.Rule; +import org.nuclearfog.twidda.model.lists.Rules; + +import java.util.Set; +import java.util.TreeSet; + +/** + * A {@link android.widget.ListView} adapter used to show instance rules and provide function to select rule items and their IDs + * + * @author nuclearfog + */ +public class RuleAdapter extends BaseAdapter { + + private GlobalSettings settings; + + private Rules items = new Rules(); + private Set selection = new TreeSet<>(); + + /** + * + */ + public RuleAdapter(Context context) { + settings = GlobalSettings.get(context); + } + + + @Override + public int getCount() { + return items.size(); + } + + + @Override + public Object getItem(int position) { + return items.get(position); + } + + + @Override + public long getItemId(int position) { + return items.get(position).getId(); + } + + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + TextView description; + ImageView button; + final Rule item = items.get(position); + if (convertView == null) { + convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rule, parent, false); + description = convertView.findViewById(R.id.item_rule_description); + button = convertView.findViewById(R.id.item_rule_select); + button.setColorFilter(settings.getIconColor()); + description.setTextColor(settings.getTextColor()); + description.setTypeface(settings.getTypeFace()); + } else { + description = convertView.findViewById(R.id.item_rule_description); + button = convertView.findViewById(R.id.item_rule_select); + } + + description.setText(item.getDescription()); + if (selection.contains(item.getId())) { + button.setImageResource(R.drawable.check); + } else { + button.setImageResource(R.drawable.circle); + } + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selection.contains(item.getId())) { + button.setImageResource(R.drawable.circle); + selection.remove(item.getId()); + } else { + button.setImageResource(R.drawable.check); + selection.add(item.getId()); + } + } + }); + return convertView; + } + + /** + * set adapter items + * + * @param rules adapter items to set + */ + public void setItems(Rules rules) { + items.clear(); + items.addAll(rules); + notifyDataSetChanged(); + } + + /** + * get user selected item IDs + * + * @return an array containing selected item IDs + */ + public long[] getSelectedIds() { + int i = 0; + long[] result = new long[selection.size()]; + for (Long select : selection) { + result[i++] = select; + } + return result; + } + + /** + * @return true if adapter doesn't contain any items + */ + public boolean isEmpty() { + return items.isEmpty(); + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nuclearfog/twidda/ui/dialogs/ReportDialog.java b/app/src/main/java/org/nuclearfog/twidda/ui/dialogs/ReportDialog.java index 0fdd16b3..af6ea244 100644 --- a/app/src/main/java/org/nuclearfog/twidda/ui/dialogs/ReportDialog.java +++ b/app/src/main/java/org/nuclearfog/twidda/ui/dialogs/ReportDialog.java @@ -7,6 +7,7 @@ import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.EditText; +import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; @@ -18,11 +19,14 @@ import com.kyleduo.switchbutton.SwitchButton; import org.nuclearfog.twidda.R; import org.nuclearfog.twidda.backend.async.AsyncExecutor.AsyncCallback; import org.nuclearfog.twidda.backend.async.ReportUpdater; +import org.nuclearfog.twidda.backend.async.RuleLoader; import org.nuclearfog.twidda.backend.helper.update.ReportUpdate; import org.nuclearfog.twidda.backend.utils.AppStyles; import org.nuclearfog.twidda.backend.utils.ErrorUtils; import org.nuclearfog.twidda.config.GlobalSettings; +import org.nuclearfog.twidda.model.lists.Rules; import org.nuclearfog.twidda.ui.adapter.listview.DropdownAdapter; +import org.nuclearfog.twidda.ui.adapter.listview.RuleAdapter; import java.io.Serializable; @@ -31,11 +35,16 @@ import java.io.Serializable; * * @author nuclearfog */ -public class ReportDialog extends Dialog implements OnClickListener, AsyncCallback { +public class ReportDialog extends Dialog implements OnClickListener { private static final String KEY_SAVE = "reportupdate-data"; - private DropdownAdapter adapter; + private AsyncCallback reportResult = this::onReportResult; + private AsyncCallback rulesResult = this::onRulesLoaded; + + private DropdownAdapter selectorAdapter; + private RuleAdapter ruleAdapter; + private RuleLoader ruleLoader; private ReportUpdater reportUpdater; private GlobalSettings settings; @@ -51,10 +60,12 @@ public class ReportDialog extends Dialog implements OnClickListener, AsyncCallba */ public ReportDialog(Activity activity) { super(activity, R.style.DefaultDialog); - adapter = new DropdownAdapter(activity.getApplicationContext()); + selectorAdapter = new DropdownAdapter(activity.getApplicationContext()); reportUpdater = new ReportUpdater(activity.getApplicationContext()); + ruleLoader = new RuleLoader(activity.getApplicationContext()); + ruleAdapter = new RuleAdapter(activity.getApplicationContext()); settings = GlobalSettings.get(getContext()); - adapter.setItems(R.array.reports); + selectorAdapter.setItems(R.array.reports); } @@ -64,18 +75,28 @@ public class ReportDialog extends Dialog implements OnClickListener, AsyncCallba setContentView(R.layout.dialog_report); ViewGroup rootView = findViewById(R.id.dialog_report_root); View reportButton = findViewById(R.id.dialog_report_apply); + ListView ruleSelector = findViewById(R.id.dialog_report_rule_selector); reportCategory = findViewById(R.id.dialog_report_category); textTitle = findViewById(R.id.dialog_report_title); switchForward = findViewById(R.id.dialog_report_switch_forward); editDescription = findViewById(R.id.dialog_report_description); AppStyles.setTheme(rootView, settings.getPopupColor()); - reportCategory.setAdapter(adapter); - + reportCategory.setAdapter(selectorAdapter); + ruleSelector.setAdapter(ruleAdapter); reportButton.setOnClickListener(this); } + @Override + protected void onStart() { + super.onStart(); + if (ruleAdapter.isEmpty() && ruleLoader.isIdle()) { + ruleLoader.execute(null, rulesResult); + } + } + + @NonNull @Override public Bundle onSaveInstanceState() { @@ -120,16 +141,37 @@ public class ReportDialog extends Dialog implements OnClickListener, AsyncCallba } else { update.setCategory(ReportUpdate.CATEGORY_OTHER); } + update.setRuleIds(ruleAdapter.getSelectedIds()); update.setComment(editDescription.getText().toString()); update.setForward(switchForward.isChecked()); - reportUpdater.execute(update, this); + reportUpdater.execute(update, reportResult); } } } + /** + * show this dialog + * + * @param userId Id of the user to report to instance + * @param statusId additional status IDs + */ + public void show(long userId, long... statusId) { + if (!isShowing()) { + super.show(); + update = new ReportUpdate(userId); + if (statusId.length > 0) { + update.setStatusIds(statusId); + textTitle.setText(R.string.dialog_report_title_status); + } else { + textTitle.setText(R.string.dialog_report_title_user); + } + } + } - @Override - public void onResult(@NonNull ReportUpdater.Result result) { + /** + * callback for {@link ReportUpdater} + */ + private void onReportResult(@NonNull ReportUpdater.Result result) { if (result.reported) { if (update != null && update.getStatusIds().length > 0) { Toast.makeText(getContext(), R.string.info_status_reported, Toast.LENGTH_SHORT).show(); @@ -142,18 +184,9 @@ public class ReportDialog extends Dialog implements OnClickListener, AsyncCallba } /** - * + * callback for {@link RuleLoader} */ - public void show(long userId, long statusId) { - if (!isShowing()) { - super.show(); - update = new ReportUpdate(userId); - if (statusId != 0L) { - update.setStatusIds(new long[]{statusId}); - textTitle.setText(R.string.dialog_report_title_status); - } else { - textTitle.setText(R.string.dialog_report_title_user); - } - } + private void onRulesLoaded(@NonNull Rules rules) { + ruleAdapter.setItems(rules); } } \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_report.xml b/app/src/main/res/layout/dialog_report.xml index ed3cc445..ed282958 100644 --- a/app/src/main/res/layout/dialog_report.xml +++ b/app/src/main/res/layout/dialog_report.xml @@ -39,11 +39,20 @@ app:layout_constraintTop_toBottomOf="@id/dialog_report_title" app:layout_constraintEnd_toEndOf="parent" /> + + diff --git a/app/src/main/res/layout/item_option.xml b/app/src/main/res/layout/item_option.xml index dd87e30d..02b890cd 100644 --- a/app/src/main/res/layout/item_option.xml +++ b/app/src/main/res/layout/item_option.xml @@ -10,18 +10,9 @@ android:layout_width="@dimen/item_option_icon_size" android:layout_height="@dimen/item_option_icon_size" android:contentDescription="@string/description_poll_vote_icon" - android:layout_marginEnd="@dimen/item_option_button_margin" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toStartOf="@id/item_option_button_barrier" /> - - + app:layout_constraintBottom_toBottomOf="parent"/> @@ -41,8 +33,9 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:thumb="@android:color/transparent" + android:layout_marginStart="@dimen/item_option_layout_padding" app:layout_constraintHorizontal_weight="3" - app:layout_constraintStart_toEndOf="@id/item_option_button_barrier" + app:layout_constraintStart_toEndOf="@id/item_option_voted_icon" app:layout_constraintTop_toBottomOf="@id/item_option_name" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> diff --git a/app/src/main/res/layout/item_rule.xml b/app/src/main/res/layout/item_rule.xml new file mode 100644 index 00000000..44431e03 --- /dev/null +++ b/app/src/main/res/layout/item_rule.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/profile.xml b/app/src/main/res/menu/profile.xml index 5f7a8674..20b5f8d9 100644 --- a/app/src/main/res/menu/profile.xml +++ b/app/src/main/res/menu/profile.xml @@ -28,6 +28,11 @@ android:title="@string/menu_mute_user" android:visible="false" /> + + 2dp + + 20sp + 5dp + 20sp 13sp 5dp - 10dp 13sp