package app.fedilab.android.mastodon.viewmodel.mastodon; /* Copyright 2021 Thomas Schneider * * This file is a part of Fedilab * * 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. * * Fedilab 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 Fedilab; if not, * see . */ import android.app.Application; import android.net.Uri; import android.os.Handler; import android.os.Looper; import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import java.net.IDN; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; import app.fedilab.android.R; import app.fedilab.android.mastodon.client.endpoints.MastodonStatusesService; import app.fedilab.android.mastodon.client.entities.api.Account; import app.fedilab.android.mastodon.client.entities.api.Accounts; import app.fedilab.android.mastodon.client.entities.api.Attachment; import app.fedilab.android.mastodon.client.entities.api.Card; import app.fedilab.android.mastodon.client.entities.api.Context; import app.fedilab.android.mastodon.client.entities.api.Pagination; import app.fedilab.android.mastodon.client.entities.api.Poll; import app.fedilab.android.mastodon.client.entities.api.ScheduledStatus; import app.fedilab.android.mastodon.client.entities.api.ScheduledStatuses; import app.fedilab.android.mastodon.client.entities.api.Status; import app.fedilab.android.mastodon.client.entities.api.StatusSource; import app.fedilab.android.mastodon.client.entities.app.BaseAccount; import app.fedilab.android.mastodon.client.entities.app.StatusCache; import app.fedilab.android.mastodon.client.entities.app.Timeline; import app.fedilab.android.mastodon.exception.DBException; import app.fedilab.android.mastodon.helper.Helper; import app.fedilab.android.mastodon.helper.MastodonHelper; import app.fedilab.android.mastodon.helper.TimelineHelper; import okhttp3.Headers; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.RequestBody; import retrofit2.Call; import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; public class StatusesVM extends AndroidViewModel { private MutableLiveData statusMutableLiveData; private MutableLiveData> statusListMutableLiveData; private MutableLiveData statusSourceMutableLiveData; private MutableLiveData scheduledStatusMutableLiveData; private MutableLiveData scheduledStatusesMutableLiveData; private MutableLiveData voidMutableLiveData; private MutableLiveData cardMutableLiveData; private MutableLiveData attachmentMutableLiveData; private MutableLiveData pollMutableLiveData; private MutableLiveData contextMutableLiveData; private MutableLiveData accountsMutableLiveData; public StatusesVM(@NonNull Application application) { super(application); } private OkHttpClient getOkHttpClient() { return new OkHttpClient.Builder() .readTimeout(60, TimeUnit.SECONDS) .connectTimeout(60, TimeUnit.SECONDS) .callTimeout(60, TimeUnit.SECONDS) .proxy(Helper.getProxy(getApplication().getApplicationContext())) .build(); } private MastodonStatusesService init(String instance) { Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://" + (instance != null ? IDN.toASCII(instance, IDN.ALLOW_UNASSIGNED) : null) + "/api/v1/") .addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder())) .client(getOkHttpClient()) .build(); return retrofit.create(MastodonStatusesService.class); } /** * Post a media * * @param instance Instance domain of the active account * @param token Access token of the active account * @param file URI * @param thumbnail URI * @param description String * @param focus String * @return LiveData */ public LiveData postAttachment(@NonNull String instance, String token, @NonNull Uri file, Uri thumbnail, String description, String focus) { MastodonStatusesService mastodonStatusesService = init(instance); attachmentMutableLiveData = new MutableLiveData<>(); new Thread(() -> { MultipartBody.Part fileMultipartBody; MultipartBody.Part thumbnailMultipartBody; fileMultipartBody = Helper.getMultipartBody(getApplication(), "file", file); thumbnailMultipartBody = Helper.getMultipartBody(getApplication(), "file", thumbnail); RequestBody descriptionBody = null; if (description != null && description.trim().length() > 0) { descriptionBody = RequestBody.create(MediaType.parse("text/plain"), description); } RequestBody focusBody = null; if (focus != null && focus.trim().length() > 0) { focusBody = RequestBody.create(MediaType.parse("text/plain"), focus); } Call attachmentCall = mastodonStatusesService.postMedia(token, fileMultipartBody, thumbnailMultipartBody, descriptionBody, focusBody); Attachment attachment = null; if (attachmentCall != null) { try { Response attachmentResponse = attachmentCall.execute(); if (attachmentResponse.isSuccessful()) { attachment = attachmentResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Attachment finalAttachment = attachment; Runnable myRunnable = () -> attachmentMutableLiveData.setValue(finalAttachment); mainHandler.post(myRunnable); }).start(); return attachmentMutableLiveData; } /** * Post a message with the authenticated user * text can be null if a media or a poll is attached * if media are attached, poll need to be null * if a poll is attached, media should be null * * @param instance Instance domain of the active account * @param token Access token of the active account * @param idempotency_Key String * @param text String * @param media_ids List * @param poll_options String * @param poll_expire_in int * @param poll_multiple boolean * @param poll_hide_totals boolean * @param in_reply_to_id String * @param sensitive boolean * @param spoiler_text String * @param visibility String * @param language String * @return LiveData */ public LiveData postStatus(@NonNull String instance, String token, String idempotency_Key, String text, List media_ids, List poll_options, Integer poll_expire_in, Boolean poll_multiple, Boolean poll_hide_totals, String in_reply_to_id, Boolean sensitive, String spoiler_text, String visibility, String language, String quote_id, String content_type) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call statusCall = mastodonStatusesService.createStatus(idempotency_Key, token, text, media_ids, poll_options, poll_expire_in, poll_multiple, poll_hide_totals, in_reply_to_id, sensitive, spoiler_text, visibility, language, quote_id, content_type); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; Runnable myRunnable = () -> statusMutableLiveData.setValue(finalStatus); mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * @param instance Instance domain of the active account * @param token Access token of the active account * Schedule a message for the authenticated user * scheduledAt can't be null * text can be null if a media or a poll is attached * if media are attached, poll need to be null * if a poll is attached, media should be null * @param idempotency_Key String * @param text String * @param media_ids List * @param poll_options String * @param poll_expire_in int * @param poll_multiple boolean * @param poll_hide_totals boolean * @param in_reply_to_id String * @param sensitive boolean * @param spoiler_text String * @param visibility String * @param scheduledAt Date * @param language String * @return LiveData */ public LiveData postScheduledStatus(@NonNull String instance, String token, String idempotency_Key, String text, List media_ids, List poll_options, Integer poll_expire_in, Boolean poll_multiple, Boolean poll_hide_totals, String in_reply_to_id, Boolean sensitive, String spoiler_text, String visibility, @NonNull String scheduledAt, String language) { MastodonStatusesService mastodonStatusesService = init(instance); scheduledStatusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call scheduledStatusCall = mastodonStatusesService.createScheduledStatus(idempotency_Key, token, text, media_ids, poll_options, poll_expire_in, poll_multiple, poll_hide_totals, in_reply_to_id, sensitive, spoiler_text, visibility, scheduledAt, language); ScheduledStatus scheduledStatus = null; if (scheduledStatusCall != null) { try { Response scheduledStatusResponse = scheduledStatusCall.execute(); if (scheduledStatusResponse.isSuccessful()) { scheduledStatus = scheduledStatusResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); ScheduledStatus finalScheduledStatus = scheduledStatus; Runnable myRunnable = () -> scheduledStatusMutableLiveData.setValue(finalScheduledStatus); mainHandler.post(myRunnable); }).start(); return scheduledStatusMutableLiveData; } /** * Get a status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData getStatus(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call statusCall = mastodonStatusesService.getStatus(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; Runnable myRunnable = () -> statusMutableLiveData.setValue(finalStatus); mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Get a status source by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData getStatusSource(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusSourceMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call statusSourceCall = mastodonStatusesService.getStatusSource(token, id); StatusSource statusSource = null; if (statusSourceCall != null) { try { Response statusResponse = statusSourceCall.execute(); if (statusResponse.isSuccessful()) { statusSource = statusResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); StatusSource finalStatusSource = statusSource; Runnable myRunnable = () -> statusSourceMutableLiveData.setValue(finalStatusSource); mainHandler.post(myRunnable); }).start(); return statusSourceMutableLiveData; } /** * Get a history of statuses by id * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData> getStatusHistory(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusListMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call> statusListCall = mastodonStatusesService.getStatusHistory(token, id); List statusList = null; if (statusListCall != null) { try { Response> statusResponse = statusListCall.execute(); if (statusResponse.isSuccessful()) { statusList = statusResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); List finalStatusList = statusList; Runnable myRunnable = () -> statusListMutableLiveData.setValue(finalStatusList); mainHandler.post(myRunnable); }).start(); return statusListMutableLiveData; } /** * Delete a status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData deleteStatus(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call statusCall = mastodonStatusesService.deleteStatus(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } //The status must also be deleted in cache try { BaseAccount account = new app.fedilab.android.mastodon.client.entities.app.Account(getApplication().getApplicationContext()).getAccountByToken(token); new StatusCache(getApplication().getApplicationContext()).deleteStatus(account.instance, id); } catch (DBException e) { e.printStackTrace(); } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; Runnable myRunnable = () -> statusMutableLiveData.setValue(finalStatus); mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Get context of a status * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData getContext(@NonNull String instance, String token, @NonNull String id) { MastodonStatusesService mastodonStatusesService = init(instance); contextMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call contextCall = mastodonStatusesService.getContext(token, id); Context context = null; if (contextCall != null) { try { Response contextResponse = contextCall.execute(); if (contextResponse.isSuccessful()) { context = contextResponse.body(); if (context != null) { TimelineHelper.filterStatus(getApplication().getApplicationContext(), context.descendants, Timeline.TimeLineEnum.CONTEXT); TimelineHelper.filterStatus(getApplication().getApplicationContext(), context.ancestors, Timeline.TimeLineEnum.CONTEXT); } } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Context finalContext = context; Runnable myRunnable = () -> contextMutableLiveData.setValue(finalContext); mainHandler.post(myRunnable); }).start(); return contextMutableLiveData; } /** * People that reblogged the status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @param max_id String * @param since_id String * @param min_id String * @return LiveData */ public LiveData rebloggedBy(@NonNull String instance, String token, @NonNull String id, String max_id, String since_id, String min_id) { MastodonStatusesService mastodonStatusesService = init(instance); accountsMutableLiveData = new MutableLiveData<>(); new Thread(() -> { int limit = MastodonHelper.accountsPerCall(getApplication().getApplicationContext()); Call> accountsCall = mastodonStatusesService.getRebloggedBy(token, id, max_id, since_id, min_id, limit); List accounts = null; Headers headers = null; if (accountsCall != null) { try { Response> accountsResponse = accountsCall.execute(); if (accountsResponse.isSuccessful()) { accounts = accountsResponse.body(); } headers = accountsResponse.headers(); } catch (Exception e) { e.printStackTrace(); } } Accounts accountsPagination = new Accounts(); accountsPagination.accounts = accounts; accountsPagination.pagination = MastodonHelper.getPagination(headers); Handler mainHandler = new Handler(Looper.getMainLooper()); Runnable myRunnable = () -> accountsMutableLiveData.setValue(accountsPagination); mainHandler.post(myRunnable); }).start(); return accountsMutableLiveData; } /** * People that favourited the status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @param max_id String * @param since_id String * @param min_id String * @return LiveData */ public LiveData favouritedBy(@NonNull String instance, String token, @NonNull String id, String max_id, String since_id, String min_id) { MastodonStatusesService mastodonStatusesService = init(instance); accountsMutableLiveData = new MutableLiveData<>(); new Thread(() -> { int limit = MastodonHelper.accountsPerCall(getApplication().getApplicationContext()); Call> accountsCall = mastodonStatusesService.getFavourited(token, id, max_id, since_id, min_id, limit); List accounts = null; Headers headers = null; if (accountsCall != null) { try { Response> accountsResponse = accountsCall.execute(); if (accountsResponse.isSuccessful()) { accounts = accountsResponse.body(); } headers = accountsResponse.headers(); } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Accounts accountsPagination = new Accounts(); accountsPagination.accounts = accounts; if (headers != null) { accountsPagination.pagination = MastodonHelper.getPagination(headers); } Runnable myRunnable = () -> accountsMutableLiveData.setValue(accountsPagination); mainHandler.post(myRunnable); }).start(); return accountsMutableLiveData; } /** * Add a status to favourites by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData favourite(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.favourites(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * remove a status from favourites by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData unFavourite(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.unFavourite(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Reblog a status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @param visibility MastodonHelper.visibility - visibility of the reblog (public, unlisted, private) * @return LiveData */ public LiveData reblog(@NonNull String instance, String token, String id, MastodonHelper.visibility visibility) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.reblog(token, id, visibility != null ? visibility.name().toLowerCase() : null); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Unreblog a status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData unReblog(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.unReblog(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Bookmark a status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData bookmark(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.bookmark(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Unbookmark a status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData unBookmark(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.unBookmark(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Mute a conversation by status ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData mute(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.muteConversation(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Unmute a conversation by a status ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData unMute(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.unMuteConversation(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Pin a status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData pin(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call statusCall = mastodonStatusesService.pin(token, id); String errorMessage = null; Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Unpin a status by ID * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData unPin(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); statusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { String errorMessage = null; Call statusCall = mastodonStatusesService.unPin(token, id); Status status = null; if (statusCall != null) { try { Response statusResponse = statusCall.execute(); if (statusResponse.isSuccessful()) { status = statusResponse.body(); } else { if (statusResponse.errorBody() != null) { errorMessage = statusResponse.errorBody().string(); } } } catch (Exception e) { e.printStackTrace(); errorMessage = e.getMessage() != null ? e.getMessage() : getApplication().getString(R.string.toast_error); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Status finalStatus = status; String finalErrorMessage = errorMessage; Runnable myRunnable = () -> { statusMutableLiveData.setValue(finalStatus); if (finalErrorMessage != null) { Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, finalErrorMessage); } }; mainHandler.post(myRunnable); }).start(); return statusMutableLiveData; } /** * Get card * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData getCard(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); cardMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call cardCall = mastodonStatusesService.getCard(token, id); Card card = null; if (cardCall != null) { try { Response cardResponse = cardCall.execute(); if (cardResponse.isSuccessful()) { card = cardResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Card finalCard = card; Runnable myRunnable = () -> cardMutableLiveData.setValue(finalCard); mainHandler.post(myRunnable); }).start(); return cardMutableLiveData; } /** * Get attachment * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData getAttachment(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); attachmentMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call attachmentCall = mastodonStatusesService.getMedia(token, id); Attachment attachment = null; if (attachmentCall != null) { try { Response attachmentResponse = attachmentCall.execute(); if (attachmentResponse.isSuccessful()) { attachment = attachmentResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Attachment finalAttachment = attachment; Runnable myRunnable = () -> attachmentMutableLiveData.setValue(finalAttachment); mainHandler.post(myRunnable); }).start(); return attachmentMutableLiveData; } /** * Update a media * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - Id of the media to update * @param file URI * @param thumbnail URI * @param description String * @param focus String * @return LiveData */ public LiveData updateAttachment(@NonNull String instance, String token, @NonNull String id, @NonNull Uri file, Uri thumbnail, String description, String focus) { MastodonStatusesService mastodonStatusesService = init(instance); attachmentMutableLiveData = new MutableLiveData<>(); new Thread(() -> { MultipartBody.Part fileMultipartBody = null; MultipartBody.Part thumbnailMultipartBody = null; fileMultipartBody = Helper.getMultipartBody(getApplication(), "file", file); thumbnailMultipartBody = Helper.getMultipartBody(getApplication(), "file", thumbnail); Call attachmentCall = mastodonStatusesService.updateMedia(token, id, fileMultipartBody, thumbnailMultipartBody, description, focus); Attachment attachment = null; if (attachmentCall != null) { try { Response attachmentResponse = attachmentCall.execute(); if (attachmentResponse.isSuccessful()) { attachment = attachmentResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Attachment finalAttachment = attachment; Runnable myRunnable = () -> attachmentMutableLiveData.setValue(finalAttachment); mainHandler.post(myRunnable); }).start(); return attachmentMutableLiveData; } /** * Get Poll * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the status * @return LiveData */ public LiveData getPoll(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); pollMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call pollCall = mastodonStatusesService.getPoll(token, id); Poll poll = null; if (pollCall != null) { try { Response pollResponse = pollCall.execute(); if (pollResponse.isSuccessful()) { poll = pollResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Poll finalPoll = poll; Runnable myRunnable = () -> pollMutableLiveData.setValue(finalPoll); mainHandler.post(myRunnable); }).start(); return pollMutableLiveData; } /** * Vote on a Poll * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the poll * @param choices int[] - array of choices * @return LiveData */ public LiveData votePoll(@NonNull String instance, String token, String id, int[] choices) { MastodonStatusesService mastodonStatusesService = init(instance); pollMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call pollCall = mastodonStatusesService.votePoll(token, id, choices); Poll poll = null; if (pollCall != null) { try { Response pollResponse = pollCall.execute(); if (pollResponse.isSuccessful()) { poll = pollResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Poll finalPoll = poll; Runnable myRunnable = () -> pollMutableLiveData.setValue(finalPoll); mainHandler.post(myRunnable); }).start(); return pollMutableLiveData; } /** * Get list of scheduled status * * @param instance Instance domain of the active account * @param token Access token of the active account * @param max_id String * @param since_id String * @param min_id String * @param limit int * @return LiveData */ public LiveData getScheduledStatuses(@NonNull String instance, String token, String max_id, String since_id, String min_id, int limit) { MastodonStatusesService mastodonStatusesService = init(instance); scheduledStatusesMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call> scheduledStatuseCall = mastodonStatusesService.getScheduledStatuses(token, max_id, since_id, min_id, limit); List scheduledStatusList = null; Pagination pagination = null; if (scheduledStatuseCall != null) { try { Response> scheduledStatusResponse = scheduledStatuseCall.execute(); if (scheduledStatusResponse.isSuccessful()) { scheduledStatusList = scheduledStatusResponse.body(); pagination = MastodonHelper.getPagination(scheduledStatusResponse.headers()); } } catch (Exception e) { e.printStackTrace(); } } ScheduledStatuses scheduledStatuses = new ScheduledStatuses(); scheduledStatuses.scheduledStatuses = scheduledStatusList; scheduledStatuses.pagination = pagination; Handler mainHandler = new Handler(Looper.getMainLooper()); Runnable myRunnable = () -> scheduledStatusesMutableLiveData.setValue(scheduledStatuses); mainHandler.post(myRunnable); }).start(); return scheduledStatusesMutableLiveData; } /** * Get a scheduled status * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the scheduled status * @return LiveData */ public LiveData getScheduledStatus(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); scheduledStatusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call scheduledStatusCall = mastodonStatusesService.getScheduledStatus(token, id); ScheduledStatus scheduledStatus = null; if (scheduledStatusCall != null) { try { Response scheduledStatusResponse = scheduledStatusCall.execute(); if (scheduledStatusResponse.isSuccessful()) { scheduledStatus = scheduledStatusResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); ScheduledStatus finalScheduledStatus = scheduledStatus; Runnable myRunnable = () -> scheduledStatusMutableLiveData.setValue(finalScheduledStatus); mainHandler.post(myRunnable); }).start(); return scheduledStatusMutableLiveData; } /** * Update a scheduled status * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the scheduled status * @return LiveData */ public LiveData updateScheduledStatus(@NonNull String instance, String token, String id, Date scheduled_at) { MastodonStatusesService mastodonStatusesService = init(instance); scheduledStatusMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call scheduledStatusCall = mastodonStatusesService.updateScheduleStatus(token, id, scheduled_at); ScheduledStatus scheduledStatus = null; if (scheduledStatusCall != null) { try { Response scheduledStatusResponse = scheduledStatusCall.execute(); if (scheduledStatusResponse.isSuccessful()) { scheduledStatus = scheduledStatusResponse.body(); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); ScheduledStatus finalScheduledStatus = scheduledStatus; Runnable myRunnable = () -> scheduledStatusMutableLiveData.setValue(finalScheduledStatus); mainHandler.post(myRunnable); }).start(); return scheduledStatusMutableLiveData; } /** * Delete a scheduled status * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id String - id of the scheduled status * @return LiveData */ public LiveData deleteScheduledStatus(@NonNull String instance, String token, String id) { MastodonStatusesService mastodonStatusesService = init(instance); voidMutableLiveData = new MutableLiveData<>(); new Thread(() -> { Call voidCall = mastodonStatusesService.deleteScheduledStatus(token, id); if (voidCall != null) { try { voidCall.execute(); } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); Runnable myRunnable = () -> voidMutableLiveData.setValue(null); mainHandler.post(myRunnable); }).start(); return voidMutableLiveData; } /** * React to a status with an emoji. * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id Local ID of an announcement * @param name Unicode emoji, or shortcode of custom emoji */ public void addReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) { MastodonStatusesService mastodonStatusesService = init(instance); new Thread(() -> { Call addReactionCall = mastodonStatusesService.addReaction(token, id, name); if (addReactionCall != null) { try { addReactionCall.execute(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } /** * Undo a react emoji to a status. * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id Local ID of an announcement * @param name Unicode emoji, or shortcode of custom emoji */ public void removeReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) { MastodonStatusesService mastodonStatusesService = init(instance); new Thread(() -> { Call removeReactionCall = mastodonStatusesService.removeReaction(token, id, name); if (removeReactionCall != null) { try { removeReactionCall.execute(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } }