Polls part 1 - displaying in timelines and voting (#1200)
* add entity classes * change data models and add database migration * add polls to StatusViewData * show poll results * add methods for vote handling * add voting interface * enable voting in TimelineFragment * update polls immediately * enable custom emojis for poll options * enable voting from search fragment * add voting layout to detailed statuses * fix tests * enable voting in ViewThreadFragment * enable voting in ConversationsFragment * small refactor for StatusBaseViewHolder
This commit is contained in:
parent
82d547caf8
commit
fd7471f2ab
36 changed files with 1637 additions and 68 deletions
|
@ -46,6 +46,7 @@ import com.keylesspalace.tusky.db.AccountEntity;
|
|||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
import com.keylesspalace.tusky.di.Injectable;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.entity.Poll;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
|
||||
import com.keylesspalace.tusky.interfaces.ReselectableFragment;
|
||||
|
@ -428,6 +429,24 @@ public class NotificationsFragment extends SFragment implements
|
|||
updateAdapter();
|
||||
}
|
||||
|
||||
public void onVoteInPoll(int position, @NonNull List<Integer> choices) {
|
||||
final Notification notification = notifications.get(position).asRight();
|
||||
final Status status = notification.getStatus();
|
||||
|
||||
timelineCases.voteInPoll(status, choices)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.as(autoDisposable(from(this)))
|
||||
.subscribe(
|
||||
(newPoll) -> setVoteForPoll(position, newPoll),
|
||||
(t) -> Log.d(TAG,
|
||||
"Failed to vote in poll: " + status.getId(), t)
|
||||
);
|
||||
}
|
||||
|
||||
private void setVoteForPoll(int position, Poll poll) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMore(@NonNull View view, int position) {
|
||||
Notification notification = notifications.get(position).asRight();
|
||||
|
|
|
@ -232,10 +232,6 @@ class SearchFragment : SFragment(), StatusActionListener {
|
|||
searchRecyclerView.post { searchAdapter.notifyItemChanged(position, updatedStatus) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "SearchFragment"
|
||||
}
|
||||
|
||||
override fun onViewAccount(id: String) {
|
||||
val intent = AccountActivity.getIntent(requireContext(), id)
|
||||
startActivity(intent)
|
||||
|
@ -247,4 +243,28 @@ class SearchFragment : SFragment(), StatusActionListener {
|
|||
startActivity(intent)
|
||||
}
|
||||
|
||||
override fun onVoteInPoll(position: Int, choices: MutableList<Int>) {
|
||||
val status = searchAdapter.getStatusAtPosition(position)
|
||||
if (status != null) {
|
||||
timelineCases.voteInPoll(status, choices)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.autoDisposable(from(this, Lifecycle.Event.ON_DESTROY))
|
||||
.subscribe({poll ->
|
||||
val viewData = ViewDataUtils.statusToViewData(
|
||||
status,
|
||||
alwaysShowSensitiveMedia
|
||||
)
|
||||
val newViewData = StatusViewData.Builder(viewData)
|
||||
.setPoll(poll)
|
||||
.createStatusViewData()
|
||||
searchAdapter.updateStatusAtPosition(newViewData, position)
|
||||
|
||||
}, { t -> Log.d(TAG, "Failed to vote in poll " + status.id, t) })
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "SearchFragment"
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ import com.keylesspalace.tusky.appstore.UnfollowEvent;
|
|||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
import com.keylesspalace.tusky.di.Injectable;
|
||||
import com.keylesspalace.tusky.entity.Filter;
|
||||
import com.keylesspalace.tusky.entity.Poll;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
|
||||
import com.keylesspalace.tusky.interfaces.ReselectableFragment;
|
||||
|
@ -620,6 +621,34 @@ public class TimelineFragment extends SFragment implements
|
|||
updateAdapter();
|
||||
}
|
||||
|
||||
public void onVoteInPoll(int position, @NonNull List<Integer> choices) {
|
||||
final Status status = statuses.get(position).asRight();
|
||||
|
||||
setVoteForPoll(position, status, status.getPoll().votedCopy(choices));
|
||||
|
||||
timelineCases.voteInPoll(status, choices)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.as(autoDisposable(from(this)))
|
||||
.subscribe(
|
||||
(newPoll) -> setVoteForPoll(position, status, newPoll),
|
||||
(t) -> Log.d(TAG,
|
||||
"Failed to vote in poll: " + status.getId(), t)
|
||||
);
|
||||
}
|
||||
|
||||
private void setVoteForPoll(int position, Status status, Poll newPoll) {
|
||||
Pair<StatusViewData.Concrete, Integer> actual =
|
||||
findStatusAndPosition(position, status);
|
||||
if (actual == null) return;
|
||||
|
||||
StatusViewData newViewData = new StatusViewData
|
||||
.Builder(actual.first)
|
||||
.setPoll(newPoll)
|
||||
.createStatusViewData();
|
||||
statuses.setPairedItem(actual.second, newViewData);
|
||||
updateAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMore(@NonNull View view, final int position) {
|
||||
super.more(statuses.get(position).asRight(), view, position);
|
||||
|
|
|
@ -42,6 +42,7 @@ import com.keylesspalace.tusky.appstore.StatusComposedEvent;
|
|||
import com.keylesspalace.tusky.appstore.StatusDeletedEvent;
|
||||
import com.keylesspalace.tusky.di.Injectable;
|
||||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.entity.Poll;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.entity.StatusContext;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
|
@ -393,6 +394,33 @@ public final class ViewThreadFragment extends SFragment implements
|
|||
adapter.setStatuses(statuses.getPairedCopy());
|
||||
}
|
||||
|
||||
public void onVoteInPoll(int position, @NonNull List<Integer> choices) {
|
||||
final Status status = statuses.get(position).getActionableStatus();
|
||||
|
||||
setVoteForPoll(position, status.getPoll().votedCopy(choices));
|
||||
|
||||
timelineCases.voteInPoll(status, choices)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.as(autoDisposable(from(this)))
|
||||
.subscribe(
|
||||
(newPoll) -> setVoteForPoll(position, newPoll),
|
||||
(t) -> Log.d(TAG,
|
||||
"Failed to vote in poll: " + status.getId(), t)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
private void setVoteForPoll(int position, Poll newPoll) {
|
||||
|
||||
StatusViewData.Concrete viewData = statuses.getPairedItem(position);
|
||||
|
||||
StatusViewData.Concrete newViewData = new StatusViewData.Builder(viewData)
|
||||
.setPoll(newPoll)
|
||||
.createStatusViewData();
|
||||
statuses.setPairedItem(position, newViewData);
|
||||
adapter.setItem(position, newViewData, true);
|
||||
}
|
||||
|
||||
private void removeAllByAccountId(String accountId) {
|
||||
Status status = null;
|
||||
if (!statuses.isEmpty()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue