diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/lists/CreateList.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/lists/CreateList.java index f30dde544..1ec4204e5 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/lists/CreateList.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/lists/CreateList.java @@ -4,16 +4,18 @@ import org.joinmastodon.android.api.MastodonAPIRequest; import org.joinmastodon.android.model.ListTimeline; public class CreateList extends MastodonAPIRequest { - public CreateList(String title, ListTimeline.RepliesPolicy repliesPolicy) { + public CreateList(String title, boolean exclusive, ListTimeline.RepliesPolicy repliesPolicy) { super(HttpMethod.POST, "/lists", ListTimeline.class); Request req = new Request(); req.title = title; + req.exclusive = exclusive; req.repliesPolicy = repliesPolicy; setRequestBody(req); } public static class Request { public String title; + public boolean exclusive; public ListTimeline.RepliesPolicy repliesPolicy; } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/lists/UpdateList.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/lists/UpdateList.java index 0a6814277..64073fd3d 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/lists/UpdateList.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/lists/UpdateList.java @@ -4,10 +4,11 @@ import org.joinmastodon.android.api.MastodonAPIRequest; import org.joinmastodon.android.model.ListTimeline; public class UpdateList extends MastodonAPIRequest { - public UpdateList(String id, String title, ListTimeline.RepliesPolicy repliesPolicy) { + public UpdateList(String id, String title, boolean exclusive, ListTimeline.RepliesPolicy repliesPolicy) { super(HttpMethod.PUT, "/lists/" + id, ListTimeline.class); CreateList.Request req = new CreateList.Request(); req.title = title; + req.exclusive = exclusive; req.repliesPolicy = repliesPolicy; setRequestBody(req); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/events/ListUpdatedCreatedEvent.java b/mastodon/src/main/java/org/joinmastodon/android/events/ListUpdatedCreatedEvent.java index 89efffda2..26e0081e6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/events/ListUpdatedCreatedEvent.java +++ b/mastodon/src/main/java/org/joinmastodon/android/events/ListUpdatedCreatedEvent.java @@ -6,10 +6,12 @@ public class ListUpdatedCreatedEvent { public final String id; public final String title; public final ListTimeline.RepliesPolicy repliesPolicy; + public final boolean exclusive; - public ListUpdatedCreatedEvent(String id, String title, ListTimeline.RepliesPolicy repliesPolicy) { + public ListUpdatedCreatedEvent(String id, String title, boolean exclusive, ListTimeline.RepliesPolicy repliesPolicy) { this.id = id; this.title = title; + this.exclusive = exclusive; this.repliesPolicy = repliesPolicy; } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java index 98d0516cc..d9b4a38e7 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java @@ -492,6 +492,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab } else if ((list = listItems.get(id)) != null) { args.putString("listID", list.id); args.putString("listTitle", list.title); + args.putBoolean("listIsExclusive", list.exclusive); if (list.repliesPolicy != null) args.putInt("repliesPolicy", list.repliesPolicy.ordinal()); Nav.go(getActivity(), ListTimelineFragment.class, args); } else if ((hashtag = hashtagsItems.get(id)) != null) { diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ListTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ListTimelineFragment.java index 0e03a19e6..bc931f919 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ListTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ListTimelineFragment.java @@ -24,7 +24,7 @@ import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.TimelineDefinition; import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.utils.UiUtils; -import org.joinmastodon.android.ui.views.ListTimelineEditor; +import org.joinmastodon.android.ui.views.ListEditor; import org.joinmastodon.android.utils.StatusFilterPredicate; import java.util.List; @@ -36,12 +36,12 @@ import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.SimpleCallback; import me.grishka.appkit.utils.V; - public class ListTimelineFragment extends PinnableStatusListFragment { private String listID; private String listTitle; @Nullable private ListTimeline.RepliesPolicy repliesPolicy; + private boolean exclusive; @Override protected boolean wantsComposeButton() { @@ -54,6 +54,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment { Bundle args = getArguments(); listID = args.getString("listID"); listTitle = args.getString("listTitle"); + exclusive = args.getBoolean("listIsExclusive"); repliesPolicy = ListTimeline.RepliesPolicy.values()[args.getInt("repliesPolicy", 0)]; setTitle(listTitle); @@ -88,8 +89,8 @@ public class ListTimelineFragment extends PinnableStatusListFragment { public boolean onOptionsItemSelected(MenuItem item) { if (super.onOptionsItemSelected(item)) return true; if (item.getItemId() == R.id.edit) { - ListTimelineEditor editor = new ListTimelineEditor(getContext()); - editor.applyList(listTitle, repliesPolicy); + ListEditor editor = new ListEditor(getContext()); + editor.applyList(listTitle, exclusive, repliesPolicy); new M3AlertDialogBuilder(getActivity()) .setTitle(R.string.sk_edit_list_title) .setIcon(R.drawable.ic_fluent_people_28_regular) @@ -97,14 +98,15 @@ public class ListTimelineFragment extends PinnableStatusListFragment { .setPositiveButton(R.string.save, (d, which) -> { String newTitle = editor.getTitle().trim(); setTitle(newTitle); - new UpdateList(listID, newTitle, editor.getRepliesPolicy()).setCallback(new Callback<>() { + new UpdateList(listID, newTitle, editor.isExclusive(), editor.getRepliesPolicy()).setCallback(new Callback<>() { @Override public void onSuccess(ListTimeline list) { if (getActivity() == null) return; setTitle(list.title); listTitle = list.title; repliesPolicy = list.repliesPolicy; - E.post(new ListUpdatedCreatedEvent(listID, listTitle, repliesPolicy)); + exclusive = list.exclusive; + E.post(new ListUpdatedCreatedEvent(listID, listTitle, exclusive, repliesPolicy)); } @Override @@ -127,7 +129,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment { @Override protected TimelineDefinition makeTimelineDefinition() { - return TimelineDefinition.ofList(listID, listTitle); + return TimelineDefinition.ofList(listID, listTitle, exclusive); } @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ListsFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ListsFragment.java index 243a104c6..6f28eb95a 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ListsFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ListsFragment.java @@ -27,7 +27,7 @@ import org.joinmastodon.android.events.ListUpdatedCreatedEvent; import org.joinmastodon.android.model.ListTimeline; import org.joinmastodon.android.ui.DividerItemDecoration; import org.joinmastodon.android.ui.M3AlertDialogBuilder; -import org.joinmastodon.android.ui.views.ListTimelineEditor; +import org.joinmastodon.android.ui.views.ListEditor; import org.joinmastodon.android.utils.ProvidesAssistContent; import java.util.ArrayList; @@ -91,18 +91,18 @@ public class ListsFragment extends RecyclerFragment implements Scr @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.create) { - ListTimelineEditor editor = new ListTimelineEditor(getContext()); + ListEditor editor = new ListEditor(getContext()); new M3AlertDialogBuilder(getActivity()) .setTitle(R.string.sk_create_list_title) .setIcon(R.drawable.ic_fluent_people_add_28_regular) .setView(editor) .setPositiveButton(R.string.sk_create, (d, which) -> - new CreateList(editor.getTitle(), editor.getRepliesPolicy()).setCallback(new Callback<>() { + new CreateList(editor.getTitle(), editor.isExclusive(), editor.getRepliesPolicy()).setCallback(new Callback<>() { @Override public void onSuccess(ListTimeline list) { data.add(0, list); adapter.notifyItemRangeInserted(0, 1); - E.post(new ListUpdatedCreatedEvent(list.id, list.title, list.repliesPolicy)); + E.post(new ListUpdatedCreatedEvent(list.id, list.title, list.exclusive, list.repliesPolicy)); } @Override @@ -185,6 +185,7 @@ public class ListsFragment extends RecyclerFragment implements Scr if (item.id.equals(event.id)) { item.title = event.title; item.repliesPolicy = event.repliesPolicy; + item.exclusive = event.exclusive; adapter.notifyItemChanged(i); break; } @@ -242,7 +243,9 @@ public class ListsFragment extends RecyclerFragment implements Scr @Override public void onBind(ListTimeline item) { title.setText(item.title); - title.setCompoundDrawablesRelativeWithIntrinsicBounds(itemView.getContext().getDrawable(R.drawable.ic_fluent_people_24_regular), null, null, null); + title.setCompoundDrawablesRelativeWithIntrinsicBounds(itemView.getContext().getDrawable( + item.exclusive ? R.drawable.ic_fluent_rss_24_regular : R.drawable.ic_fluent_people_24_regular + ), null, null, null); if (profileAccountId != null) { Boolean checked = userInList.get(item.id); listToggle.setVisibility(View.VISIBLE); @@ -263,6 +266,7 @@ public class ListsFragment extends RecyclerFragment implements Scr args.putString("account", accountID); args.putString("listID", item.id); args.putString("listTitle", item.title); + args.putBoolean("listIsExclusive", item.exclusive); if (item.repliesPolicy != null) args.putInt("repliesPolicy", item.repliesPolicy.ordinal()); Nav.go(getActivity(), ListTimelineFragment.class, args); } diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/ListTimeline.java b/mastodon/src/main/java/org/joinmastodon/android/model/ListTimeline.java index 9344756da..4bd06e935 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/ListTimeline.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/ListTimeline.java @@ -14,6 +14,7 @@ public class ListTimeline extends BaseModel { @RequiredField public String title; public RepliesPolicy repliesPolicy; + public boolean exclusive; @NonNull @Override @@ -22,6 +23,7 @@ public class ListTimeline extends BaseModel { "id='" + id + '\'' + ", title='" + title + '\'' + ", repliesPolicy=" + repliesPolicy + + ", exclusive=" + exclusive + '}'; } diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/TimelineDefinition.java b/mastodon/src/main/java/org/joinmastodon/android/model/TimelineDefinition.java index 32b4d0da3..24d51b203 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/TimelineDefinition.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/TimelineDefinition.java @@ -30,18 +30,20 @@ public class TimelineDefinition { private @Nullable String listId; private @Nullable String listTitle; + private boolean listIsExclusive; private @Nullable String hashtagName; - public static TimelineDefinition ofList(String listId, String listTitle) { + public static TimelineDefinition ofList(String listId, String listTitle, boolean listIsExclusive) { TimelineDefinition def = new TimelineDefinition(TimelineType.LIST); def.listId = listId; def.listTitle = listTitle; + def.listIsExclusive = listIsExclusive; return def; } public static TimelineDefinition ofList(ListTimeline list) { - return ofList(list.id, list.title); + return ofList(list.id, list.title, list.exclusive); } public static TimelineDefinition ofHashtag(String hashtag) { @@ -99,7 +101,7 @@ public class TimelineDefinition { case LOCAL -> Icon.LOCAL; case FEDERATED -> Icon.FEDERATED; case POST_NOTIFICATIONS -> Icon.POST_NOTIFICATIONS; - case LIST -> Icon.LIST; + case LIST -> listIsExclusive ? Icon.EXCLUSIVE_LIST : Icon.LIST; case HASHTAG -> Icon.HASHTAG; case BUBBLE -> Icon.BUBBLE; }; @@ -155,6 +157,7 @@ public class TimelineDefinition { def.title = title; def.listId = listId; def.listTitle = listTitle; + def.listIsExclusive = listIsExclusive; def.hashtagName = hashtagName; def.icon = icon == null ? null : Icon.values()[icon.ordinal()]; return def; @@ -164,6 +167,7 @@ public class TimelineDefinition { if (type == TimelineType.LIST) { args.putString("listTitle", title); args.putString("listID", listId); + args.putBoolean("listIsExclusive", listIsExclusive); } else if (type == TimelineType.HASHTAG) { args.putString("hashtag", hashtagName); } @@ -179,6 +183,7 @@ public class TimelineDefinition { CITY(R.drawable.ic_fluent_city_24_regular, R.string.sk_icon_city), IMAGE(R.drawable.ic_fluent_image_24_regular, R.string.sk_icon_image), NEWS(R.drawable.ic_fluent_news_24_regular, R.string.sk_icon_news), + FEED(R.drawable.ic_fluent_rss_24_regular, R.string.sk_icon_feed), COLOR_PALETTE(R.drawable.ic_fluent_color_24_regular, R.string.sk_icon_color_palette), CAT(R.drawable.ic_fluent_animal_cat_24_regular, R.string.sk_icon_cat), DOG(R.drawable.ic_fluent_animal_dog_24_regular, R.string.sk_icon_dog), @@ -233,6 +238,7 @@ public class TimelineDefinition { FEDERATED(R.drawable.ic_fluent_earth_24_regular, R.string.sk_timeline_federated, true), POST_NOTIFICATIONS(R.drawable.ic_fluent_chat_24_regular, R.string.sk_timeline_posts, true), LIST(R.drawable.ic_fluent_people_24_regular, R.string.sk_list, true), + EXCLUSIVE_LIST(R.drawable.ic_fluent_rss_24_regular, R.string.sk_exclusive_list, true), HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true), BUBBLE(R.drawable.ic_fluent_circle_24_regular, R.string.sk_timeline_bubble, true); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/views/ListTimelineEditor.java b/mastodon/src/main/java/org/joinmastodon/android/ui/views/ListEditor.java similarity index 76% rename from mastodon/src/main/java/org/joinmastodon/android/ui/views/ListTimelineEditor.java rename to mastodon/src/main/java/org/joinmastodon/android/ui/views/ListEditor.java index e4438199e..1ebe466d2 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/views/ListTimelineEditor.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/views/ListEditor.java @@ -9,6 +9,7 @@ import android.view.MenuItem; import android.widget.Button; import android.widget.LinearLayout; import android.widget.PopupMenu; +import android.widget.Switch; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -16,18 +17,20 @@ import androidx.annotation.Nullable; import org.joinmastodon.android.R; import org.joinmastodon.android.model.ListTimeline; -public class ListTimelineEditor extends LinearLayout { +public class ListEditor extends LinearLayout { private ListTimeline.RepliesPolicy policy = null; private final TextInputFrameLayout input; private final Button button; + private final Switch exclusiveSwitch; @SuppressLint("ClickableViewAccessibility") - public ListTimelineEditor(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + public ListEditor(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); LayoutInflater.from(context).inflate(R.layout.list_timeline_editor, this); button = findViewById(R.id.button); input = findViewById(R.id.input); + exclusiveSwitch = findViewById(R.id.exclusive_checkbox); PopupMenu popupMenu = new PopupMenu(context, button, Gravity.CENTER_HORIZONTAL); popupMenu.inflate(R.menu.list_reply_policies); @@ -36,12 +39,15 @@ public class ListTimelineEditor extends LinearLayout { button.setOnTouchListener(popupMenu.getDragToOpenListener()); button.setOnClickListener(v->popupMenu.show()); input.getEditText().setHint(context.getString(R.string.sk_list_name_hint)); + findViewById(R.id.exclusive) + .setOnClickListener(v -> exclusiveSwitch.setChecked(!exclusiveSwitch.isChecked())); setRepliesPolicy(ListTimeline.RepliesPolicy.LIST); } - public void applyList(String title, @Nullable ListTimeline.RepliesPolicy policy) { + public void applyList(String title, boolean exclusive, @Nullable ListTimeline.RepliesPolicy policy) { input.getEditText().setText(title); + exclusiveSwitch.setChecked(exclusive); if (policy != null) setRepliesPolicy(policy); } @@ -53,6 +59,10 @@ public class ListTimelineEditor extends LinearLayout { return policy; } + public boolean isExclusive() { + return exclusiveSwitch.isChecked(); + } + public void setRepliesPolicy(@NonNull ListTimeline.RepliesPolicy policy) { this.policy = policy; switch (policy) { @@ -73,15 +83,15 @@ public class ListTimelineEditor extends LinearLayout { return true; } - public ListTimelineEditor(Context context, AttributeSet attrs, int defStyleAttr) { + public ListEditor(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } - public ListTimelineEditor(Context context, AttributeSet attrs) { + public ListEditor(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public ListTimelineEditor(Context context) { + public ListEditor(Context context) { this(context, null); } } diff --git a/mastodon/src/main/res/drawable/ic_fluent_rss_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_rss_24_regular.xml new file mode 100644 index 000000000..bd74d83a1 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_rss_24_regular.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/mastodon/src/main/res/layout/list_timeline_editor.xml b/mastodon/src/main/res/layout/list_timeline_editor.xml index 2a1c6a385..31362bd4f 100644 --- a/mastodon/src/main/res/layout/list_timeline_editor.xml +++ b/mastodon/src/main/res/layout/list_timeline_editor.xml @@ -39,4 +39,53 @@ android:id="@+id/input" android:layout_width="match_parent" android:layout_height="wrap_content" /> + + + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/strings_sk.xml b/mastodon/src/main/res/values/strings_sk.xml index 68e378e6d..dccf9cca8 100644 --- a/mastodon/src/main/res/values/strings_sk.xml +++ b/mastodon/src/main/res/values/strings_sk.xml @@ -227,6 +227,7 @@ Human Globe Pin + Feed Edit timeline Edit timelines ALT @@ -305,4 +306,7 @@ nobody others “Forward report” switch default + Exclusive list + Make list exclusive + Members of an exclusive list will not show up on your home timeline – if your instance supports it. \ No newline at end of file