Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

List timelines #286

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.joinmastodon.android.api.requests.lists;

import com.google.gson.reflect.TypeToken;

import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.ListTimeline;

import java.util.List;

public class GetLists extends MastodonAPIRequest<List<ListTimeline>>{
public GetLists() {
super(HttpMethod.GET, "/lists", new TypeToken<>(){});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.joinmastodon.android.api.requests.timelines;

import com.google.gson.reflect.TypeToken;

import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;

import java.util.List;

public class GetListTimeline extends MastodonAPIRequest<List<Status>> {
public GetListTimeline(String listID, String maxID, String minID, int limit, String sinceID) {
super(HttpMethod.GET, "/timelines/list/"+listID, new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(minID!=null)
addQueryParameter("min_id", minID);
if(limit>0)
addQueryParameter("limit", ""+limit);
if(sinceID!=null)
addQueryParameter("since_id", sinceID);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package org.joinmastodon.android.fragments;

import android.app.Activity;
import android.media.MediaRouter;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;

import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.timelines.GetListTimeline;
import org.joinmastodon.android.model.Status;

import java.util.List;

import me.grishka.appkit.Nav;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.V;


public class ListTimelineFragment extends StatusListFragment {
private String listID;
private String listTitle;
private ImageButton fab;

public ListTimelineFragment() {
setListLayoutId(R.layout.recycler_fragment_with_fab);
}

@Override
public void onAttach(Activity activity){
super.onAttach(activity);
listID=getArguments().getString("listID");
listTitle=getArguments().getString("listTitle");
setTitle(listTitle);
}

@Override
protected void doLoadData(int offset, int count) {
currentRequest=new GetListTimeline(listID, offset==0 ? null : getMaxID(), null, count, null)
.setCallback(new SimpleCallback<>(this) {
@Override
public void onSuccess(List<Status> result) {
onDataLoaded(result, !result.isEmpty());
}
})
.exec(accountID);
}

@Override
protected void onShown() {
super.onShown();
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
loadData();
}

@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
fab=view.findViewById(R.id.fab);
fab.setOnClickListener(this::onFabClick);
}

private void onFabClick(View v){
Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("prefilledText", listID+' ');
Nav.go(getActivity(), ComposeFragment.class, args);
}

@Override
protected void onSetFabBottomInset(int inset) {
((ViewGroup.MarginLayoutParams) fab.getLayoutParams()).bottomMargin=V.dp(24)+inset;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.joinmastodon.android.fragments;

import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.RecyclerView;

import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.lists.GetLists;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.model.ListTimeline;
import org.joinmastodon.android.ui.utils.UiUtils;

import java.util.List;

import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.fragments.BaseRecyclerFragment;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.views.UsableRecyclerView;

public class ListTimelinesFragment extends BaseRecyclerFragment<ListTimeline> implements ScrollableToTop {
private String accountId;

public ListTimelinesFragment() {
super(10);
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
accountId=getArguments().getString("account");
}

@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetLists()
.setCallback(new SimpleCallback<>(this) {
@Override
public void onSuccess(List<ListTimeline> result) {
onDataLoaded(result, false);
}
})
.exec(accountId);
}

@Override
protected RecyclerView.Adapter getAdapter() {
return new ListsAdapter();
}

@Override
public void scrollToTop() {
smoothScrollRecyclerViewToTop(list);
}

private class ListsAdapter extends RecyclerView.Adapter<ListViewHolder>{
@NonNull
@Override
public ListViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
return new ListViewHolder();
}

@Override
public void onBindViewHolder(@NonNull ListViewHolder holder, int position) {
holder.bind(data.get(position));
}

@Override
public int getItemCount() {
return data.size();
}
}

private class ListViewHolder extends BindableViewHolder<ListTimeline> implements UsableRecyclerView.Clickable{
private final TextView title;

public ListViewHolder(){
super(getActivity(), R.layout.item_list_timeline, list);
title=findViewById(R.id.title);
}

@Override
public void onBind(ListTimeline item) {
title.setText(item.title);
}

@Override
public void onClick() {
UiUtils.openListTimeline(getActivity(), accountId, item);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.fragments.ListTimelinesFragment;
import org.joinmastodon.android.ui.SimpleViewHolder;
import org.joinmastodon.android.ui.tabs.TabLayout;
import org.joinmastodon.android.ui.tabs.TabLayoutMediator;
Expand Down Expand Up @@ -51,6 +52,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
private DiscoverAccountsFragment accountsFragment;
private SearchFragment searchFragment;
private LocalTimelineFragment localTimelineFragment;
private ListTimelinesFragment listTimelinesFragment;

private String accountID;
private Runnable searchDebouncer=this::onSearchChangedDebounced;
Expand All @@ -72,7 +74,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
tabLayout=view.findViewById(R.id.tabbar);
pager=view.findViewById(R.id.pager);

tabViews=new FrameLayout[5];
tabViews=new FrameLayout[6];
for(int i=0;i<tabViews.length;i++){
FrameLayout tabView=new FrameLayout(getActivity());
tabView.setId(switch(i){
Expand All @@ -81,6 +83,7 @@ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
case 2 -> R.id.discover_news;
case 3 -> R.id.discover_local_timeline;
case 4 -> R.id.discover_users;
case 5 -> R.id.discover_lists;
default -> throw new IllegalStateException("Unexpected value: "+i);
});
tabView.setVisibility(View.GONE);
Expand Down Expand Up @@ -126,12 +129,16 @@ public void onPageSelected(int position){
localTimelineFragment=new LocalTimelineFragment();
localTimelineFragment.setArguments(args);

listTimelinesFragment=new ListTimelinesFragment();
listTimelinesFragment.setArguments(args);

getChildFragmentManager().beginTransaction()
.add(R.id.discover_posts, postsFragment)
.add(R.id.discover_local_timeline, localTimelineFragment)
.add(R.id.discover_hashtags, hashtagsFragment)
.add(R.id.discover_news, newsFragment)
.add(R.id.discover_users, accountsFragment)
.add(R.id.discover_lists, listTimelinesFragment)
.commit();
}

Expand All @@ -144,6 +151,7 @@ public void onConfigureTab(@NonNull TabLayout.Tab tab, int position){
case 2 -> R.string.news;
case 3 -> R.string.local_timeline;
case 4 -> R.string.for_you;
case 5 -> R.string.list_timelines;
default -> throw new IllegalStateException("Unexpected value: "+position);
});
tab.view.textView.setAllCaps(true);
Expand Down Expand Up @@ -271,6 +279,7 @@ private Fragment getFragmentForPage(int page){
case 2 -> newsFragment;
case 3 -> localTimelineFragment;
case 4 -> accountsFragment;
case 5 -> listTimelinesFragment;
default -> throw new IllegalStateException("Unexpected value: "+page);
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.joinmastodon.android.model;

import com.google.gson.annotations.SerializedName;

import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;

@Parcel
public class ListTimeline extends BaseModel {
@RequiredField
public String id;
@RequiredField
public String title;
@RequiredField
public RepliesPolicy repliesPolicy;

@Override
public String toString() {
return "List{" +
"id='" + id + '\'' +
", title='" + title + '\'' +
", repliesPolicy=" + repliesPolicy +
'}';
}

public enum RepliesPolicy{
@SerializedName("followed")
FOLLOWED,
@SerializedName("list")
LIST,
@SerializedName("none")
NONE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,12 @@
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusDeletedEvent;
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
import org.joinmastodon.android.fragments.ListTimelineFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.ListTimeline;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
Expand Down Expand Up @@ -294,6 +296,14 @@ public static void openHashtagTimeline(Context context, String accountID, String
Nav.go((Activity)context, HashtagTimelineFragment.class, args);
}

public static void openListTimeline(Context context, String accountID, ListTimeline list){
Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("listID", list.id);
args.putString("listTitle", list.title);
Nav.go((Activity)context, ListTimelineFragment.class, args);
}

public static void showConfirmationAlert(Context context, @StringRes int title, @StringRes int message, @StringRes int confirmButton, Runnable onConfirmed){
showConfirmationAlert(context, context.getString(title), context.getString(message), context.getString(confirmButton), onConfirmed);
}
Expand Down
19 changes: 19 additions & 0 deletions mastodon/src/main/res/layout/item_list_timeline.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="64dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="12dp">

<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_large"
android:singleLine="true"
android:ellipsize="end"
tools:text="List"/>

</RelativeLayout>
1 change: 1 addition & 0 deletions mastodon/src/main/res/values/ids.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<item name="discover_news" type="id"/>
<item name="discover_users" type="id"/>
<item name="discover_local_timeline" type="id"/>
<item name="discover_lists" type="id"/>

<item name="notifications_all" type="id"/>
<item name="notifications_mentions" type="id"/>
Expand Down
1 change: 1 addition & 0 deletions mastodon/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,5 @@
<string name="privacy_policy_title">Mastodon and your privacy</string>
<string name="privacy_policy_subtitle">Although the Mastodon app does not collect any data, the server you sign up through may have a different policy. Take a minute to review and agree to the Mastodon app privacy policy and your server\'s privacy policy.</string>
<string name="i_agree">I Agree</string>
<string name="list_timelines">Lists</string>
</resources>