Account timelines

This commit is contained in:
Grishka 2022-01-18 22:49:14 +03:00
parent ba75aa6d91
commit dc836b58f8
11 changed files with 107 additions and 10 deletions

View File

@ -32,10 +32,12 @@ dependencies {
implementation 'me.grishka.litex:recyclerview:1.2.1' implementation 'me.grishka.litex:recyclerview:1.2.1'
implementation 'me.grishka.litex:swiperefreshlayout:1.1.0' implementation 'me.grishka.litex:swiperefreshlayout:1.1.0'
implementation 'me.grishka.litex:browser:1.4.0' implementation 'me.grishka.litex:browser:1.4.0'
implementation 'me.grishka.appkit:appkit:1.1.1' implementation 'me.grishka.appkit:appkit:1.2'
implementation 'com.google.code.gson:gson:2.8.9' implementation 'com.google.code.gson:gson:2.8.9'
implementation 'org.jsoup:jsoup:1.14.3' implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8' implementation 'com.squareup:otto:1.3.8'
implementation 'de.psdev:async-otto:1.0.3' implementation 'de.psdev:async-otto:1.0.3'
implementation 'org.parceler:parceler-api:1.1.12'
annotationProcessor 'org.parceler:parceler:1.1.12'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
} }

View File

@ -0,0 +1,20 @@
package org.joinmastodon.android.api.requests.accounts;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
import java.util.List;
public class GetAccountStatuses extends MastodonAPIRequest<List<Status>>{
public GetAccountStatuses(String id, String maxID, String minID, int limit){
super(HttpMethod.GET, "/accounts/"+id+"/statuses", new TypeToken<>(){});
if(maxID!=null)
addQueryParameter("max_id", maxID);
if(minID!=null)
addQueryParameter("min_id", minID);
if(limit>0)
addQueryParameter("limit", ""+limit);
}
}

View File

@ -21,14 +21,12 @@ import me.grishka.appkit.Nav;
import me.grishka.appkit.api.SimpleCallback; import me.grishka.appkit.api.SimpleCallback;
public class HomeTimelineFragment extends StatusListFragment{ public class HomeTimelineFragment extends StatusListFragment{
private String accountID;
@Override @Override
public void onAttach(Activity activity){ public void onAttach(Activity activity){
super.onAttach(activity); super.onAttach(activity);
setTitle(R.string.app_name); setTitle(R.string.app_name);
setHasOptionsMenu(true); setHasOptionsMenu(true);
accountID=getArguments().getString("account");
loadData(); loadData();
} }

View File

@ -0,0 +1,44 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.os.Bundle;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Status;
import org.parceler.Parcels;
import java.util.List;
import me.grishka.appkit.api.SimpleCallback;
public class ProfileFragment extends StatusListFragment{
private Account user;
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
user=Parcels.unwrap(getArguments().getParcelable("profileAccount"));
setTitle("@"+user.acct);
loadData();
}
@Override
protected void doLoadData(int offset, int count){
String maxID;
if(offset>0 && !preloadedData.isEmpty())
maxID=preloadedData.get(preloadedData.size()-1).id;
else if(offset>0 && !data.isEmpty())
maxID=data.get(data.size()-1).id;
else
maxID=null;
currentRequest=new GetAccountStatuses(user.id, maxID, null, count)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Status> result){
onDataLoaded(result, !result.isEmpty());
}
})
.exec(accountID);
}
}

View File

@ -1,5 +1,6 @@
package org.joinmastodon.android.fragments; package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.view.ViewGroup; import android.view.ViewGroup;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
@ -19,7 +20,8 @@ import me.grishka.appkit.views.UsableRecyclerView;
public abstract class StatusListFragment extends BaseRecyclerFragment<Status>{ public abstract class StatusListFragment extends BaseRecyclerFragment<Status>{
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>(); protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
private DisplayItemsAdapter adapter; protected DisplayItemsAdapter adapter;
protected String accountID;
public StatusListFragment(){ public StatusListFragment(){
super(20); super(20);
@ -30,11 +32,17 @@ public abstract class StatusListFragment extends BaseRecyclerFragment<Status>{
return adapter=new DisplayItemsAdapter(); return adapter=new DisplayItemsAdapter();
} }
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
accountID=getArguments().getString("account");
}
@Override @Override
public void onAppendItems(List<Status> items){ public void onAppendItems(List<Status> items){
super.onAppendItems(items); super.onAppendItems(items);
for(Status s:items){ for(Status s:items){
displayItems.addAll(StatusDisplayItem.buildItems(this, s)); displayItems.addAll(StatusDisplayItem.buildItems(this, s, accountID));
} }
} }
@ -48,7 +56,7 @@ public abstract class StatusListFragment extends BaseRecyclerFragment<Status>{
data.addAll(0, items); data.addAll(0, items);
int offset=0; int offset=0;
for(Status s:items){ for(Status s:items){
List<StatusDisplayItem> toAdd=StatusDisplayItem.buildItems(this, s); List<StatusDisplayItem> toAdd=StatusDisplayItem.buildItems(this, s, accountID);
displayItems.addAll(offset, toAdd); displayItems.addAll(offset, toAdd);
offset+=toAdd.size(); offset+=toAdd.size();
} }

View File

@ -2,6 +2,7 @@ package org.joinmastodon.android.model;
import org.joinmastodon.android.api.ObjectValidationException; import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField; import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDate; import java.time.LocalDate;
@ -10,6 +11,7 @@ import java.util.List;
/** /**
* Represents a user of Mastodon and their associated profile. * Represents a user of Mastodon and their associated profile.
*/ */
@Parcel
public class Account extends BaseModel{ public class Account extends BaseModel{
// Base attributes // Base attributes

View File

@ -1,12 +1,14 @@
package org.joinmastodon.android.model; package org.joinmastodon.android.model;
import org.joinmastodon.android.api.RequiredField; import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;
import java.time.Instant; import java.time.Instant;
/** /**
* Represents a profile field as a name-value pair with optional verification. * Represents a profile field as a name-value pair with optional verification.
*/ */
@Parcel
public class AccountField extends BaseModel{ public class AccountField extends BaseModel{
/** /**
* The key of a given field's key-value pair. * The key of a given field's key-value pair.

View File

@ -1,10 +1,12 @@
package org.joinmastodon.android.model; package org.joinmastodon.android.model;
import org.joinmastodon.android.api.RequiredField; import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;
/** /**
* Represents a custom emoji. * Represents a custom emoji.
*/ */
@Parcel
public class Emoji extends BaseModel{ public class Emoji extends BaseModel{
/** /**
* The name of the custom emoji. * The name of the custom emoji.

View File

@ -2,12 +2,14 @@ package org.joinmastodon.android.model;
import org.joinmastodon.android.api.ObjectValidationException; import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField; import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;
import java.util.List; import java.util.List;
/** /**
* Represents display or publishing preferences of user's own account. Returned as an additional entity when verifying and updated credentials, as an attribute of Account. * Represents display or publishing preferences of user's own account. Returned as an additional entity when verifying and updated credentials, as an attribute of Account.
*/ */
@Parcel
public class Source extends BaseModel{ public class Source extends BaseModel{
/** /**
* Profile bio. * Profile bio.

View File

@ -1,19 +1,24 @@
package org.joinmastodon.android.ui.displayitems; package org.joinmastodon.android.ui.displayitems;
import android.app.Activity; import android.app.Activity;
import android.graphics.Bitmap; import android.app.Fragment;
import android.graphics.drawable.Animatable; import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
import org.parceler.Parcels;
import java.time.Instant; import java.time.Instant;
import me.grishka.appkit.Nav;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder; import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
@ -23,12 +28,16 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
private Account user; private Account user;
private Instant createdAt; private Instant createdAt;
private ImageLoaderRequest avaRequest; private ImageLoaderRequest avaRequest;
private Fragment parentFragment;
private String accountID;
public HeaderStatusDisplayItem(Status status, Account user, Instant createdAt){ public HeaderStatusDisplayItem(Status status, Account user, Instant createdAt, Fragment parentFragment, String accountID){
super(status); super(status);
this.user=user; this.user=user;
this.createdAt=createdAt; this.createdAt=createdAt;
avaRequest=new UrlImageLoaderRequest(user.avatar); avaRequest=new UrlImageLoaderRequest(user.avatar);
this.parentFragment=parentFragment;
this.accountID=accountID;
} }
@Override @Override
@ -54,6 +63,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
name=findViewById(R.id.name); name=findViewById(R.id.name);
subtitle=findViewById(R.id.subtitle); subtitle=findViewById(R.id.subtitle);
avatar=findViewById(R.id.avatar); avatar=findViewById(R.id.avatar);
avatar.setOnClickListener(this::onAvaClick);
} }
@Override @Override
@ -73,5 +83,12 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
public void clearImage(int index){ public void clearImage(int index){
avatar.setImageBitmap(null); avatar.setImageBitmap(null);
} }
private void onAvaClick(View v){
Bundle args=new Bundle();
args.putString("account", item.accountID);
args.putParcelable("profileAccount", Parcels.wrap(item.user));
Nav.go(item.parentFragment.getActivity(), ProfileFragment.class, args);
}
} }
} }

View File

@ -42,13 +42,13 @@ public abstract class StatusDisplayItem{
}; };
} }
public static List<StatusDisplayItem> buildItems(Fragment fragment, Status status){ public static List<StatusDisplayItem> buildItems(Fragment fragment, Status status, String accountID){
ArrayList<StatusDisplayItem> items=new ArrayList<>(); ArrayList<StatusDisplayItem> items=new ArrayList<>();
Status statusForContent=status.reblog==null ? status : status.reblog; Status statusForContent=status.reblog==null ? status : status.reblog;
if(status.reblog!=null){ if(status.reblog!=null){
items.add(new ReblogOrReplyLineStatusDisplayItem(status)); items.add(new ReblogOrReplyLineStatusDisplayItem(status));
} }
items.add(new HeaderStatusDisplayItem(status, statusForContent.account, statusForContent.createdAt)); items.add(new HeaderStatusDisplayItem(status, statusForContent.account, statusForContent.createdAt, fragment, accountID));
if(!TextUtils.isEmpty(statusForContent.content)) if(!TextUtils.isEmpty(statusForContent.content))
items.add(new TextStatusDisplayItem(status, HtmlParser.parse(statusForContent.content, statusForContent.emojis), fragment)); items.add(new TextStatusDisplayItem(status, HtmlParser.parse(statusForContent.content, statusForContent.emojis), fragment));
for(Attachment attachment:statusForContent.mediaAttachments){ for(Attachment attachment:statusForContent.mediaAttachments){