add the ability to see who faved or boosted a toot (#962)

* move reblog/fav count up in detailed status view and make them clickable

* use status object returned by api when reblogging/faving

* Reblogs -> Boosts

* add support for viewing who faved/reblogged a status

* add onShowReblogs/onShowFavs to listener, fix display bug

* remove unneeded icon from previous revision

* small code improvements

* fix liking/boosting toot with card
This commit is contained in:
Konrad Pozniak 2018-12-27 09:48:24 +01:00 committed by GitHub
commit c869886c19
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 651 additions and 648 deletions

View file

@ -1,404 +0,0 @@
/* Copyright 2017 Andrew Dawson
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.fragment;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.snackbar.Snackbar;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.keylesspalace.tusky.AccountActivity;
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.adapter.AccountAdapter;
import com.keylesspalace.tusky.adapter.BlocksAdapter;
import com.keylesspalace.tusky.adapter.FollowAdapter;
import com.keylesspalace.tusky.adapter.FollowRequestsAdapter;
import com.keylesspalace.tusky.adapter.MutesAdapter;
import com.keylesspalace.tusky.di.Injectable;
import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Relationship;
import com.keylesspalace.tusky.interfaces.AccountActionListener;
import com.keylesspalace.tusky.network.MastodonApi;
import com.keylesspalace.tusky.util.HttpHeaderLink;
import com.keylesspalace.tusky.util.ThemeUtils;
import com.keylesspalace.tusky.view.EndlessOnScrollListener;
import java.util.List;
import javax.inject.Inject;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class AccountListFragment extends BaseFragment implements AccountActionListener,
Injectable {
private static final String TAG = "AccountList"; // logging tag
public AccountListFragment() {
}
public enum Type {
FOLLOWS,
FOLLOWERS,
BLOCKS,
MUTES,
FOLLOW_REQUESTS,
}
@Inject
public MastodonApi api;
private Type type;
private String accountId;
private LinearLayoutManager layoutManager;
private RecyclerView recyclerView;
private EndlessOnScrollListener scrollListener;
private AccountAdapter adapter;
private boolean fetching = false;
private String bottomId;
public static AccountListFragment newInstance(Type type) {
Bundle arguments = new Bundle();
AccountListFragment fragment = new AccountListFragment();
arguments.putSerializable("type", type);
fragment.setArguments(arguments);
return fragment;
}
public static AccountListFragment newInstance(Type type, String accountId) {
Bundle arguments = new Bundle();
AccountListFragment fragment = new AccountListFragment();
arguments.putSerializable("type", type);
arguments.putString("accountId", accountId);
fragment.setArguments(arguments);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
type = (Type) arguments.getSerializable("type");
accountId = arguments.getString("accountId");
api = null;
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_account_list, container, false);
Context context = getContext();
recyclerView = rootView.findViewById(R.id.recycler_view);
recyclerView.setHasFixedSize(true);
layoutManager = new LinearLayoutManager(context);
recyclerView.setLayoutManager(layoutManager);
DividerItemDecoration divider = new DividerItemDecoration(
context, layoutManager.getOrientation());
Drawable drawable = ThemeUtils.getDrawable(context, R.attr.status_divider_drawable,
R.drawable.status_divider_dark);
divider.setDrawable(drawable);
recyclerView.addItemDecoration(divider);
scrollListener = null;
if (type == Type.BLOCKS) {
adapter = new BlocksAdapter(this);
} else if (type == Type.MUTES) {
adapter = new MutesAdapter(this);
} else if (type == Type.FOLLOW_REQUESTS) {
adapter = new FollowRequestsAdapter(this);
} else {
adapter = new FollowAdapter(this);
}
recyclerView.setAdapter(adapter);
return rootView;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Just use the basic scroll listener to load more accounts.
scrollListener = new EndlessOnScrollListener(layoutManager) {
@Override
public void onLoadMore(int totalItemsCount, RecyclerView view) {
AccountListFragment.this.onLoadMore();
}
};
recyclerView.addOnScrollListener(scrollListener);
fetchAccounts(null);
}
@Override
public void onViewAccount(String id) {
Context context = getContext();
if(context != null) {
Intent intent = AccountActivity.getIntent(context, id);
startActivity(intent);
}
}
@Override
public void onMute(final boolean mute, final String id, final int position) {
Callback<Relationship> callback = new Callback<Relationship>() {
@Override
public void onResponse(@NonNull Call<Relationship> call, @NonNull Response<Relationship> response) {
if (response.isSuccessful()) {
onMuteSuccess(mute, id, position);
} else {
onMuteFailure(mute, id);
}
}
@Override
public void onFailure(@NonNull Call<Relationship> call, @NonNull Throwable t) {
onMuteFailure(mute, id);
}
};
Call<Relationship> call;
if (!mute) {
call = api.unmuteAccount(id);
} else {
call = api.muteAccount(id);
}
callList.add(call);
call.enqueue(callback);
}
private void onMuteSuccess(boolean muted, final String id, final int position) {
if (muted) {
return;
}
final MutesAdapter mutesAdapter = (MutesAdapter) adapter;
final Account unmutedUser = mutesAdapter.removeItem(position);
View.OnClickListener listener = v -> {
mutesAdapter.addItem(unmutedUser, position);
onMute(true, id, position);
};
Snackbar.make(recyclerView, R.string.confirmation_unmuted, Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo, listener)
.show();
}
private void onMuteFailure(boolean mute, String id) {
String verb;
if (mute) {
verb = "mute";
} else {
verb = "unmute";
}
Log.e(TAG, String.format("Failed to %s account id %s", verb, id));
}
@Override
public void onBlock(final boolean block, final String id, final int position) {
Callback<Relationship> cb = new Callback<Relationship>() {
@Override
public void onResponse(@NonNull Call<Relationship> call, @NonNull Response<Relationship> response) {
if (response.isSuccessful()) {
onBlockSuccess(block, id, position);
} else {
onBlockFailure(block, id);
}
}
@Override
public void onFailure(@NonNull Call<Relationship> call, @NonNull Throwable t) {
onBlockFailure(block, id);
}
};
Call<Relationship> call;
if (!block) {
call = api.unblockAccount(id);
} else {
call = api.blockAccount(id);
}
callList.add(call);
call.enqueue(cb);
}
private void onBlockSuccess(boolean blocked, final String id, final int position) {
if (blocked) {
return;
}
final BlocksAdapter blocksAdapter = (BlocksAdapter) adapter;
final Account unblockedUser = blocksAdapter.removeItem(position);
View.OnClickListener listener = v -> {
blocksAdapter.addItem(unblockedUser, position);
onBlock(true, id, position);
};
Snackbar.make(recyclerView, R.string.confirmation_unblocked, Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo, listener)
.show();
}
private void onBlockFailure(boolean block, String id) {
String verb;
if (block) {
verb = "block";
} else {
verb = "unblock";
}
Log.e(TAG, String.format("Failed to %s account id %s", verb, id));
}
@Override
public void onRespondToFollowRequest(final boolean accept, final String accountId,
final int position) {
Callback<Relationship> callback = new Callback<Relationship>() {
@Override
public void onResponse(@NonNull Call<Relationship> call, @NonNull Response<Relationship> response) {
if (response.isSuccessful()) {
onRespondToFollowRequestSuccess(position);
} else {
onRespondToFollowRequestFailure(accept, accountId);
}
}
@Override
public void onFailure(@NonNull Call<Relationship> call, @NonNull Throwable t) {
onRespondToFollowRequestFailure(accept, accountId);
}
};
Call<Relationship> call;
if (accept) {
call = api.authorizeFollowRequest(accountId);
} else {
call = api.rejectFollowRequest(accountId);
}
callList.add(call);
call.enqueue(callback);
}
private void onRespondToFollowRequestSuccess(int position) {
FollowRequestsAdapter followRequestsAdapter = (FollowRequestsAdapter) adapter;
followRequestsAdapter.removeItem(position);
}
private void onRespondToFollowRequestFailure(boolean accept, String accountId) {
String verb;
if (accept) {
verb = "accept";
} else {
verb = "reject";
}
String message = String.format("Failed to %s account id %s.", verb, accountId);
Log.e(TAG, message);
}
private Call<List<Account>> getFetchCallByListType(Type type, String fromId) {
switch (type) {
default:
case FOLLOWS:
return api.accountFollowing(accountId, fromId, null, null);
case FOLLOWERS:
return api.accountFollowers(accountId, fromId, null, null);
case BLOCKS:
return api.blocks(fromId, null, null);
case MUTES:
return api.mutes(fromId, null, null);
case FOLLOW_REQUESTS:
return api.followRequests(fromId, null, null);
}
}
private void fetchAccounts(String id) {
if (fetching) {
return;
}
fetching = true;
if (id != null) {
recyclerView.post(() -> adapter.setBottomLoading(true));
}
Callback<List<Account>> cb = new Callback<List<Account>>() {
@Override
public void onResponse(@NonNull Call<List<Account>> call, @NonNull Response<List<Account>> response) {
if (response.isSuccessful()) {
String linkHeader = response.headers().get("Link");
onFetchAccountsSuccess(response.body(), linkHeader);
} else {
onFetchAccountsFailure(new Exception(response.message()));
}
}
@Override
public void onFailure(@NonNull Call<List<Account>> call, @NonNull Throwable t) {
onFetchAccountsFailure((Exception) t);
}
};
Call<List<Account>> listCall = getFetchCallByListType(type, id);
callList.add(listCall);
listCall.enqueue(cb);
}
private void onFetchAccountsSuccess(List<Account> accounts, String linkHeader) {
adapter.setBottomLoading(false);
List<HttpHeaderLink> links = HttpHeaderLink.parse(linkHeader);
HttpHeaderLink next = HttpHeaderLink.findByRelationType(links, "next");
String fromId = null;
if (next != null) {
fromId = next.uri.getQueryParameter("max_id");
}
if (adapter.getItemCount() > 1) {
adapter.addItems(accounts);
} else {
adapter.update(accounts);
}
bottomId = fromId;
fetching = false;
adapter.setBottomLoading(false);
}
private void onFetchAccountsFailure(Exception exception) {
fetching = false;
Log.e(TAG, "Fetch failure: " + exception.getMessage());
}
private void onLoadMore() {
if(bottomId == null) {
return;
}
fetchAccounts(bottomId);
}
}

View file

@ -0,0 +1,336 @@
/* Copyright 2017 Andrew Dawson
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.fragment
import android.os.Bundle
import com.google.android.material.snackbar.Snackbar
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.keylesspalace.tusky.AccountActivity
import com.keylesspalace.tusky.AccountListActivity.Type
import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.adapter.AccountAdapter
import com.keylesspalace.tusky.adapter.BlocksAdapter
import com.keylesspalace.tusky.adapter.FollowAdapter
import com.keylesspalace.tusky.adapter.FollowRequestsAdapter
import com.keylesspalace.tusky.adapter.MutesAdapter
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.Account
import com.keylesspalace.tusky.entity.Relationship
import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.util.HttpHeaderLink
import com.keylesspalace.tusky.util.ThemeUtils
import com.keylesspalace.tusky.view.EndlessOnScrollListener
import kotlinx.android.synthetic.main.fragment_account_list.*
import javax.inject.Inject
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
@Inject
lateinit var api: MastodonApi
private lateinit var type: Type
private var id: String? = null
private lateinit var scrollListener: EndlessOnScrollListener
private lateinit var adapter: AccountAdapter
private var fetching = false
private var bottomId: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
type = arguments?.getSerializable(ARG_TYPE) as Type
id = arguments?.getString(ARG_ID)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_account_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
recyclerView.setHasFixedSize(true)
val layoutManager = LinearLayoutManager(context)
recyclerView.layoutManager = layoutManager
val divider = DividerItemDecoration(context, layoutManager.orientation)
val drawable = ThemeUtils.getDrawable(context, R.attr.status_divider_drawable, R.drawable.status_divider_dark)
divider.setDrawable(drawable)
recyclerView.addItemDecoration(divider)
adapter = when(type) {
Type.BLOCKS -> BlocksAdapter(this)
Type.MUTES -> MutesAdapter(this)
Type.FOLLOW_REQUESTS -> FollowRequestsAdapter(this)
else -> FollowAdapter(this)
}
recyclerView.adapter = adapter
scrollListener = object : EndlessOnScrollListener(layoutManager) {
override fun onLoadMore(totalItemsCount: Int, view: RecyclerView) {
if (bottomId == null) {
return
}
fetchAccounts(bottomId)
}
}
recyclerView.addOnScrollListener(scrollListener)
fetchAccounts()
}
override fun onViewAccount(id: String) {
(activity as BaseActivity?)?.let {
val intent = AccountActivity.getIntent(it, id)
it.startActivityWithSlideInAnimation(intent)
}
}
override fun onMute(mute: Boolean, id: String, position: Int) {
val callback = object : Callback<Relationship> {
override fun onResponse(call: Call<Relationship>, response: Response<Relationship>) {
if (response.isSuccessful) {
onMuteSuccess(mute, id, position)
} else {
onMuteFailure(mute, id)
}
}
override fun onFailure(call: Call<Relationship>, t: Throwable) {
onMuteFailure(mute, id)
}
}
val call = if (!mute) {
api.unmuteAccount(id)
} else {
api.muteAccount(id)
}
callList.add(call)
call.enqueue(callback)
}
private fun onMuteSuccess(muted: Boolean, id: String, position: Int) {
if (muted) {
return
}
val mutesAdapter = adapter as MutesAdapter
val unmutedUser = mutesAdapter.removeItem(position)
if(unmutedUser != null) {
Snackbar.make(recyclerView, R.string.confirmation_unmuted, Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo) {
mutesAdapter.addItem(unmutedUser, position)
onMute(true, id, position)
}
.show()
}
}
private fun onMuteFailure(mute: Boolean, accountId: String) {
val verb = if (mute) {
"mute"
} else {
"unmute"
}
Log.e(TAG, "Failed to $verb account id $accountId")
}
override fun onBlock(block: Boolean, id: String, position: Int) {
val cb = object : Callback<Relationship> {
override fun onResponse(call: Call<Relationship>, response: Response<Relationship>) {
if (response.isSuccessful) {
onBlockSuccess(block, id, position)
} else {
onBlockFailure(block, id)
}
}
override fun onFailure(call: Call<Relationship>, t: Throwable) {
onBlockFailure(block, id)
}
}
val call = if (!block) {
api.unblockAccount(id)
} else {
api.blockAccount(id)
}
callList.add(call)
call.enqueue(cb)
}
private fun onBlockSuccess(blocked: Boolean, id: String, position: Int) {
if (blocked) {
return
}
val blocksAdapter = adapter as BlocksAdapter
val unblockedUser = blocksAdapter.removeItem(position)
if(unblockedUser != null) {
Snackbar.make(recyclerView, R.string.confirmation_unblocked, Snackbar.LENGTH_LONG)
.setAction(R.string.action_undo) {
blocksAdapter.addItem(unblockedUser, position)
onBlock(true, id, position)
}
.show()
}
}
private fun onBlockFailure(block: Boolean, accountId: String) {
val verb = if (block) {
"block"
} else {
"unblock"
}
Log.e(TAG, "Failed to $verb account accountId $accountId")
}
override fun onRespondToFollowRequest(accept: Boolean, accountId: String,
position: Int) {
val callback = object : Callback<Relationship> {
override fun onResponse(call: Call<Relationship>, response: Response<Relationship>) {
if (response.isSuccessful) {
onRespondToFollowRequestSuccess(position)
} else {
onRespondToFollowRequestFailure(accept, accountId)
}
}
override fun onFailure(call: Call<Relationship>, t: Throwable) {
onRespondToFollowRequestFailure(accept, accountId)
}
}
val call = if (accept) {
api.authorizeFollowRequest(accountId)
} else {
api.rejectFollowRequest(accountId)
}
callList.add(call)
call.enqueue(callback)
}
private fun onRespondToFollowRequestSuccess(position: Int) {
val followRequestsAdapter = adapter as FollowRequestsAdapter
followRequestsAdapter.removeItem(position)
}
private fun onRespondToFollowRequestFailure(accept: Boolean, accountId: String) {
val verb = if (accept) {
"accept"
} else {
"reject"
}
Log.e(TAG, "Failed to $verb account id $accountId.")
}
private fun getFetchCallByListType(type: Type, fromId: String?): Call<List<Account>> {
return when (type) {
Type.FOLLOWS -> api.accountFollowing(id, fromId)
Type.FOLLOWERS -> api.accountFollowers(id, fromId)
Type.BLOCKS -> api.blocks(fromId)
Type.MUTES -> api.mutes(fromId)
Type.FOLLOW_REQUESTS -> api.followRequests(fromId)
Type.REBLOGGED -> api.statusRebloggedBy(id, fromId)
Type.FAVOURITED -> api.statusFavouritedBy(id, fromId)
}
}
private fun fetchAccounts(id: String? = null) {
if (fetching) {
return
}
fetching = true
if (id != null) {
recyclerView.post { adapter.setBottomLoading(true) }
}
val cb = object : Callback<List<Account>> {
override fun onResponse(call: Call<List<Account>>, response: Response<List<Account>>) {
val accountList = response.body()
if (response.isSuccessful && accountList != null) {
val linkHeader = response.headers().get("Link")
onFetchAccountsSuccess(accountList, linkHeader)
} else {
onFetchAccountsFailure(Exception(response.message()))
}
}
override fun onFailure(call: Call<List<Account>>, t: Throwable) {
onFetchAccountsFailure(t as Exception)
}
}
val listCall = getFetchCallByListType(type, id)
callList.add(listCall)
listCall.enqueue(cb)
}
private fun onFetchAccountsSuccess(accounts: List<Account>, linkHeader: String?) {
adapter.setBottomLoading(false)
val links = HttpHeaderLink.parse(linkHeader)
val next = HttpHeaderLink.findByRelationType(links, "next")
val fromId = next?.uri?.getQueryParameter("max_id")
if (adapter.itemCount > 0) {
adapter.addItems(accounts)
} else {
adapter.update(accounts)
}
bottomId = fromId
fetching = false
}
private fun onFetchAccountsFailure(exception: Exception) {
fetching = false
Log.e(TAG, "Fetch failure", exception)
}
companion object {
private const val TAG = "AccountList" // logging tag
private const val ARG_TYPE = "type"
private const val ARG_ID = "id"
fun newInstance(type: Type, id: String? = null): AccountListFragment {
return AccountListFragment().apply {
arguments = Bundle(2).apply {
putSerializable(ARG_TYPE, type)
putString(ARG_ID, id)
}
}
}
}
}

View file

@ -18,6 +18,7 @@ package com.keylesspalace.tusky.fragment;
import androidx.arch.core.util.Function;
import androidx.lifecycle.Lifecycle;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@ -37,6 +38,8 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.keylesspalace.tusky.AccountListActivity;
import com.keylesspalace.tusky.BaseActivity;
import com.keylesspalace.tusky.BuildConfig;
import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.ViewThreadActivity;
@ -237,7 +240,8 @@ public final class ViewThreadFragment extends SFragment implements
@Override
public void onResponse(@NonNull Call<Status> call, @NonNull Response<Status> response) {
if (response.isSuccessful()) {
setReblogForStatus(position, status, reblog);
updateStatus(position, response.body());
eventHub.dispatch(new ReblogEvent(status.getId(), reblog));
}
}
@ -250,24 +254,6 @@ public final class ViewThreadFragment extends SFragment implements
});
}
private void setReblogForStatus(int position, Status status, boolean reblog) {
status.setReblogged(reblog);
if (status.getReblog() != null) {
status.getReblog().setReblogged(reblog);
}
StatusViewData.Concrete viewdata = statuses.getPairedItem(position);
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder((viewdata));
viewDataBuilder.setReblogged(reblog);
StatusViewData.Concrete newViewData = viewDataBuilder.createStatusViewData();
statuses.setPairedItem(position, newViewData);
adapter.setItem(position, newViewData, true);
}
@Override
public void onFavourite(final boolean favourite, final int position) {
final Status status = statuses.get(position);
@ -275,7 +261,8 @@ public final class ViewThreadFragment extends SFragment implements
@Override
public void onResponse(@NonNull Call<Status> call, @NonNull Response<Status> response) {
if (response.isSuccessful()) {
setFavForStatus(position, status, favourite);
updateStatus(position, response.body());
eventHub.dispatch(new FavoriteEvent(status.getId(), favourite));
}
}
@ -288,22 +275,20 @@ public final class ViewThreadFragment extends SFragment implements
});
}
private void setFavForStatus(int position, Status status, boolean favourite) {
status.setFavourited(favourite);
private void updateStatus(int position, Status status) {
if(position >= 0 && position < statuses.size()) {
statuses.set(position, status);
if(position == statusIndex && card != null) {
StatusViewData.Concrete viewData = new StatusViewData.Builder(statuses.getPairedItem(position))
.setCard(card)
.createStatusViewData();
statuses.setPairedItem(position, viewData);
}
adapter.setItem(position, statuses.getPairedItem(position), true);
if (status.getReblog() != null) {
status.getReblog().setFavourited(favourite);
}
StatusViewData.Concrete viewdata = statuses.getPairedItem(position);
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder((viewdata));
viewDataBuilder.setFavourited(favourite);
StatusViewData.Concrete newViewData = viewDataBuilder.createStatusViewData();
statuses.setPairedItem(position, newViewData);
adapter.setItem(position, newViewData, true);
}
@Override
@ -355,10 +340,24 @@ public final class ViewThreadFragment extends SFragment implements
}
@Override
public void onLoadMore(int pos) {
public void onLoadMore(int position) {
}
@Override
public void onShowReblogs(int position) {
String statusId = statuses.get(position).getId();
Intent intent = AccountListActivity.newIntent(getContext(), AccountListActivity.Type.REBLOGGED, statusId);
((BaseActivity) getActivity()).startActivityWithSlideInAnimation(intent);
}
@Override
public void onShowFavs(int position) {
String statusId = statuses.get(position).getId();
Intent intent = AccountListActivity.newIntent(getContext(), AccountListActivity.Type.FAVOURITED, statusId);
((BaseActivity) getActivity()).startActivityWithSlideInAnimation(intent);
}
@Override
public void onContentCollapsedChange(boolean isCollapsed, int position) {
if (position < 0 || position >= statuses.size()) {
@ -615,14 +614,44 @@ public final class ViewThreadFragment extends SFragment implements
Pair<Integer, Status> posAndStatus = findStatusAndPos(event.getStatusId());
if (posAndStatus == null) return;
//noinspection ConstantConditions
setFavForStatus(posAndStatus.first, posAndStatus.second, event.getFavourite());
boolean favourite = event.getFavourite();
posAndStatus.second.setFavourited(favourite);
if (posAndStatus.second.getReblog() != null) {
posAndStatus.second.getReblog().setFavourited(favourite);
}
StatusViewData.Concrete viewdata = statuses.getPairedItem(posAndStatus.first);
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder((viewdata));
viewDataBuilder.setFavourited(favourite);
StatusViewData.Concrete newViewData = viewDataBuilder.createStatusViewData();
statuses.setPairedItem(posAndStatus.first, newViewData);
adapter.setItem(posAndStatus.first, newViewData, true);
}
private void handleReblogEvent(ReblogEvent event) {
Pair<Integer, Status> posAndStatus = findStatusAndPos(event.getStatusId());
if (posAndStatus == null) return;
//noinspection ConstantConditions
setReblogForStatus(posAndStatus.first, posAndStatus.second, event.getReblog());
boolean reblog = event.getReblog();
posAndStatus.second.setReblogged(reblog);
if (posAndStatus.second.getReblog() != null) {
posAndStatus.second.getReblog().setReblogged(reblog);
}
StatusViewData.Concrete viewdata = statuses.getPairedItem(posAndStatus.first);
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder((viewdata));
viewDataBuilder.setReblogged(reblog);
StatusViewData.Concrete newViewData = viewDataBuilder.createStatusViewData();
statuses.setPairedItem(posAndStatus.first, newViewData);
adapter.setItem(posAndStatus.first, newViewData, true);
}
private void handleStatusComposedEvent(StatusComposedEvent event) {