commit - a4f512fa7a99d7d5e510ea2cec0efa0d721d42a1
commit + 3f6b305219492b01af706e58faf00679164ebb6b
blob - 3aebcd1ad8674971d61d33d43f0dc8792596edc6 (mode 644)
blob + /dev/null
--- mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java
+++ /dev/null
-package org.joinmastodon.android.api.session;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.text.TextUtils;
-import android.util.Log;
-
-import org.joinmastodon.android.E;
-import org.joinmastodon.android.MastodonApp;
-import org.joinmastodon.android.R;
-import org.joinmastodon.android.api.CacheController;
-import org.joinmastodon.android.api.MastodonAPIController;
-import org.joinmastodon.android.api.PushSubscriptionManager;
-import org.joinmastodon.android.api.StatusInteractionController;
-import org.joinmastodon.android.api.requests.accounts.GetPreferences;
-import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentialsPreferences;
-import org.joinmastodon.android.api.requests.markers.GetMarkers;
-import org.joinmastodon.android.api.requests.markers.SaveMarkers;
-import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
-import org.joinmastodon.android.events.NotificationsMarkerUpdatedEvent;
-import org.joinmastodon.android.model.Account;
-import org.joinmastodon.android.model.AltTextFilter;
-import org.joinmastodon.android.model.Application;
-import org.joinmastodon.android.model.FilterAction;
-import org.joinmastodon.android.model.FilterContext;
-import org.joinmastodon.android.model.FilterResult;
-import org.joinmastodon.android.model.Instance;
-import org.joinmastodon.android.model.FollowList;
-import org.joinmastodon.android.model.LegacyFilter;
-import org.joinmastodon.android.model.Preferences;
-import org.joinmastodon.android.model.PushSubscription;
-import org.joinmastodon.android.model.Status;
-import org.joinmastodon.android.model.TimelineMarkers;
-import org.joinmastodon.android.model.Token;
-import org.joinmastodon.android.utils.ObjectIdComparator;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Consumer;
-import java.util.function.Function;
-
-import me.grishka.appkit.api.Callback;
-import me.grishka.appkit.api.ErrorResponse;
-
-public class AccountSession{
- private static final String TAG="AccountSession";
-
- public Token token;
- public Account self;
- public String domain;
- public Application app;
- public long infoLastUpdated;
- public boolean activated=true;
- public String pushPrivateKey;
- public String pushPublicKey;
- public String pushAuthKey;
- public PushSubscription pushSubscription;
- public boolean needUpdatePushSettings;
- public long filtersLastUpdated;
- public List<LegacyFilter> wordFilters=new ArrayList<>();
- public String pushAccountID;
- public AccountActivationInfo activationInfo;
- public Preferences preferences;
- private transient MastodonAPIController apiController;
- private transient StatusInteractionController statusInteractionController, remoteStatusInteractionController;
- private transient CacheController cacheController;
- private transient PushSubscriptionManager pushSubscriptionManager;
- private transient SharedPreferences prefs;
- private transient boolean preferencesNeedSaving;
- private transient AccountLocalPreferences localPreferences;
- private transient List<FollowList> lists;
-
- AccountSession(Token token, Account self, Application app, String domain, boolean activated, AccountActivationInfo activationInfo){
- this.token=token;
- this.self=self;
- this.domain=domain;
- this.app=app;
- this.activated=activated;
- this.activationInfo=activationInfo;
- infoLastUpdated=System.currentTimeMillis();
- }
-
- AccountSession(){}
-
- public String getID(){
- return domain+"_"+self.id;
- }
-
- public MastodonAPIController getApiController(){
- if(apiController==null)
- apiController=new MastodonAPIController(this);
- return apiController;
- }
-
- public StatusInteractionController getStatusInteractionController(){
- if(statusInteractionController==null)
- statusInteractionController=new StatusInteractionController(getID());
- return statusInteractionController;
- }
-
- public StatusInteractionController getRemoteStatusInteractionController(){
- if(remoteStatusInteractionController==null)
- remoteStatusInteractionController=new StatusInteractionController(getID(), false);
- return remoteStatusInteractionController;
- }
-
- public CacheController getCacheController(){
- if(cacheController==null)
- cacheController=new CacheController(getID());
- return cacheController;
- }
-
- public PushSubscriptionManager getPushSubscriptionManager(){
- if(pushSubscriptionManager==null)
- pushSubscriptionManager=new PushSubscriptionManager(getID());
- return pushSubscriptionManager;
- }
-
- public String getFullUsername(){
- return '@'+self.username+'@'+domain;
- }
-
- public void preferencesFromAccountSource(Account account) {
- if (account != null && account.source != null && preferences != null) {
- if (account.source.privacy != null)
- preferences.postingDefaultVisibility = account.source.privacy;
- if (account.source.language != null)
- preferences.postingDefaultLanguage = account.source.language;
- }
- }
-
- public void reloadPreferences(Consumer<Preferences> callback){
- new GetPreferences()
- .setCallback(new Callback<>(){
- @Override
- public void onSuccess(Preferences result){
- preferences=result;
- preferencesFromAccountSource(self);
- if(callback!=null)
- callback.accept(result);
- AccountSessionManager.getInstance().writeAccountsFile();
- }
-
- @Override
- public void onError(ErrorResponse error){
- Log.w(TAG, "Failed to load preferences for account "+getID()+": "+error);
- if (preferences==null)
- preferences=new Preferences();
- preferencesFromAccountSource(self);
- }
- })
- .exec(getID());
- }
-
- public SharedPreferences getRawLocalPreferences(){
- if(prefs==null)
- prefs=MastodonApp.context.getSharedPreferences(getID(), Context.MODE_PRIVATE);
- return prefs;
- }
-
- public void reloadNotificationsMarker(Consumer<String> callback){
- new GetMarkers()
- .setCallback(new Callback<>(){
- @Override
- public void onSuccess(TimelineMarkers result){
- if(result.notifications!=null && !TextUtils.isEmpty(result.notifications.lastReadId)){
- String id=result.notifications.lastReadId;
- String lastKnown=getLastKnownNotificationsMarker();
- if(ObjectIdComparator.INSTANCE.compare(id, lastKnown)<0){
- // Marker moved back -- previous marker update must have failed.
- // Pretend it didn't happen and repeat the request.
- id=lastKnown;
- new SaveMarkers(null, id).exec(getID());
- }
- callback.accept(id);
- setNotificationsMarker(id, false);
- }
- }
-
- @Override
- public void onError(ErrorResponse error){}
- })
- .exec(getID());
- }
-
- public String getLastKnownNotificationsMarker(){
- return getRawLocalPreferences().getString("notificationsMarker", null);
- }
-
- public void setNotificationsMarker(String id, boolean clearUnread){
- getRawLocalPreferences().edit().putString("notificationsMarker", id).apply();
- E.post(new NotificationsMarkerUpdatedEvent(getID(), id, clearUnread));
- }
-
- public void logOut(Activity activity, Runnable onDone){
- new RevokeOauthToken(app.clientId, app.clientSecret, token.accessToken)
- .setCallback(new Callback<>(){
- @Override
- public void onSuccess(Object result){
- AccountSessionManager.getInstance().removeAccount(getID());
- onDone.run();
- }
-
- @Override
- public void onError(ErrorResponse error){
- AccountSessionManager.getInstance().removeAccount(getID());
- onDone.run();
- }
- })
- .wrapProgress(activity, R.string.loading, false)
- .exec(getID());
- }
-
- public void savePreferencesLater(){
- preferencesNeedSaving=true;
- }
-
- public void savePreferencesIfPending(){
- if(preferencesNeedSaving){
- new UpdateAccountCredentialsPreferences(preferences, self.locked, self.discoverable, self.source.indexable)
- .setCallback(new Callback<>(){
- @Override
- public void onSuccess(Account result){
- preferencesNeedSaving=false;
- self=result;
- AccountSessionManager.getInstance().writeAccountsFile();
- }
-
- @Override
- public void onError(ErrorResponse error){
- Log.e(TAG, "failed to save preferences: "+error);
- }
- })
- .exec(getID());
- }
- }
-
- public AccountLocalPreferences getLocalPreferences(){
- if(localPreferences==null)
- localPreferences=new AccountLocalPreferences(getRawLocalPreferences(), this);
- return localPreferences;
- }
-
- public void filterStatuses(List<Status> statuses, FilterContext context){
- filterStatuses(statuses, context, null);
- }
-
- public void filterStatuses(List<Status> statuses, FilterContext context, Account profile){
- filterStatusContainingObjects(statuses, Function.identity(), context, profile);
- }
-
- public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context){
- filterStatusContainingObjects(objects, extractor, context, null);
- }
-
- private boolean statusIsOnOwnProfile(Status s, Account profile){
- return self != null && profile != null && s.account != null
- && Objects.equals(self.id, profile.id) && Objects.equals(self.id, s.account.id);
- }
-
- private boolean isFilteredType(Status s){
- AccountLocalPreferences localPreferences = getLocalPreferences();
- return (!localPreferences.showReplies && s.inReplyToId != null)
- || (!localPreferences.showBoosts && s.reblog != null);
- }
-
- public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context, Account profile){
- AccountLocalPreferences localPreferences = getLocalPreferences();
- if(!localPreferences.serverSideFiltersSupported) for(T obj:objects){
- Status s=extractor.apply(obj);
- if(s!=null && s.filtered!=null){
- localPreferences.serverSideFiltersSupported=true;
- localPreferences.save();
- break;
- }
- }
-
- List<T> removeUs=new ArrayList<>();
- for(int i=0; i<objects.size(); i++){
- T o=objects.get(i);
- if(filterStatusContainingObject(o, extractor, context, profile)){
- Status s=extractor.apply(o);
- removeUs.add(o);
- if(s!=null && s.hasGapAfter!=null && i>0){
- // oops, we're about to remove an item that has a gap after...
- // gotta find the previous status that's not also about to be removed
- for(int j=i-1; j>=0; j--){
- T p=objects.get(j);
- Status prev=extractor.apply(objects.get(j));
- if(prev!=null && !removeUs.contains(p)){
- prev.hasGapAfter=s.hasGapAfter;
- break;
- }
- }
- }
- }
- }
- objects.removeAll(removeUs);
- }
-
- public <T> boolean filterStatusContainingObject(T object, Function<T, Status> extractor, FilterContext context, Account profile){
- Status s=extractor.apply(object);
- if(s==null)
- return false;
- // don't hide own posts in own profile
- if(statusIsOnOwnProfile(s, profile))
- return false;
- if(isFilteredType(s) && (context == FilterContext.HOME || context == FilterContext.PUBLIC))
- return true;
- // Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
- if(getLocalPreferences().serverSideFiltersSupported){
- // Moshidon: this code path in CustomLocalTimelines makes the app crash, so this check is here
- if (s.filtered == null)
- return false;
- for(FilterResult filter : s.filtered){
- if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE && filter.filter.context.contains(context))
- return true;
- }
- }else if(wordFilters!=null){
- for(LegacyFilter filter : wordFilters){
- if(filter.context.contains(context) && filter.matches(s) && filter.isActive())
- return true;
- }
- }
- return false;
- }
-
- public List<FilterResult> getClientSideFilters(Status status) {
- List<FilterResult> filters = new ArrayList<>();
-
- // filter post that have no alt text
- // it only applies when activated in the settings
- AltTextFilter altTextFilter=new AltTextFilter(FilterAction.WARN, EnumSet.allOf(FilterContext.class));
- if(altTextFilter.matches(status)){
- FilterResult filterResult=new FilterResult();
- filterResult.filter=altTextFilter;
- filterResult.keywordMatches=List.of();
- filters.add(filterResult);
- }
- return filters;
- }
-
- public void updateAccountInfo(){
- AccountSessionManager.getInstance().updateSessionLocalInfo(this);
- }
-
- public Optional<Instance> getInstance() {
- return Optional.ofNullable(AccountSessionManager.getInstance().getInstanceInfo(domain));
- }
-
- public Uri getInstanceUri() {
- return new Uri.Builder()
- .scheme("https")
- .authority(getInstance().map(i -> i.normalizedUri).orElse(domain))
- .build();
- }
-
- public String getDefaultAvatarUrl() {
- return getInstance()
- .map(instance->"https://"+domain+(instance.isAkkoma() ? "/images/avi.png" : "/avatars/original/missing.png"))
- .orElse("");
- }
-
- public boolean isNotificationsMentionsOnly(){
- return getRawLocalPreferences().getBoolean("notificationsMentionsOnly", false);
- }
-
- public void setNotificationsMentionsOnly(boolean mentionsOnly){
- getRawLocalPreferences().edit().putBoolean("notificationsMentionsOnly", mentionsOnly).apply();
- }
-}
blob - /dev/null
blob + c55bb9e9b37fa74dc67e69b9df7982f24caf81cf (mode 644)
--- /dev/null
+++ mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.kt
+package org.joinmastodon.android.api.session
+
+import android.app.Activity
+import android.content.Context
+import android.content.SharedPreferences
+import android.net.Uri
+import android.text.TextUtils
+import android.util.Log
+import me.grishka.appkit.api.Callback
+import me.grishka.appkit.api.ErrorResponse
+import org.joinmastodon.android.E
+import org.joinmastodon.android.MastodonApp
+import org.joinmastodon.android.R
+import org.joinmastodon.android.api.CacheController
+import org.joinmastodon.android.api.MastodonAPIController
+import org.joinmastodon.android.api.PushSubscriptionManager
+import org.joinmastodon.android.api.StatusInteractionController
+import org.joinmastodon.android.api.requests.accounts.GetPreferences
+import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentialsPreferences
+import org.joinmastodon.android.api.requests.markers.GetMarkers
+import org.joinmastodon.android.api.requests.markers.SaveMarkers
+import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken
+import org.joinmastodon.android.events.NotificationsMarkerUpdatedEvent
+import org.joinmastodon.android.model.Account
+import org.joinmastodon.android.model.AltTextFilter
+import org.joinmastodon.android.model.Application
+import org.joinmastodon.android.model.FilterAction
+import org.joinmastodon.android.model.FilterContext
+import org.joinmastodon.android.model.FilterResult
+import org.joinmastodon.android.model.Instance
+import org.joinmastodon.android.model.LegacyFilter
+import org.joinmastodon.android.model.Preferences
+import org.joinmastodon.android.model.PushSubscription
+import org.joinmastodon.android.model.Status
+import org.joinmastodon.android.model.TimelineMarkers
+import org.joinmastodon.android.model.Token
+import org.joinmastodon.android.utils.ObjectIdComparator
+import java.util.EnumSet
+import java.util.Optional
+import java.util.function.Consumer
+import java.util.function.Function
+
+class AccountSession {
+ @JvmField
+ var token: Token? = null
+ @JvmField
+ var self: Account? = null
+ @JvmField
+ var domain: String? = null
+ @JvmField
+ var app: Application? = null
+ @JvmField
+ var infoLastUpdated: Long = 0
+ @JvmField
+ var activated: Boolean = true
+ @JvmField
+ var pushPrivateKey: String? = null
+ @JvmField
+ var pushPublicKey: String? = null
+ @JvmField
+ var pushAuthKey: String? = null
+ @JvmField
+ var pushSubscription: PushSubscription? = null
+ @JvmField
+ var needUpdatePushSettings: Boolean = false
+ @JvmField
+ var filtersLastUpdated: Long = 0
+ @JvmField
+ var wordFilters: MutableList<LegacyFilter>? = ArrayList()
+ @JvmField
+ var pushAccountID: String? = null
+ @JvmField
+ var activationInfo: AccountActivationInfo? = null
+ @JvmField
+ var preferences: Preferences? = null
+
+ val lastKnownNotificationsMarker: String?
+ get() = this.rawLocalPreferences?.getString("notificationsMarker", null)
+
+ @Transient
+ var apiController: MastodonAPIController? = null
+ get() {
+ if (field == null) field = MastodonAPIController(this)
+ return field
+ }
+ private set
+
+ @Transient
+ var statusInteractionController: StatusInteractionController? = null
+ get() {
+ if (field == null) field = StatusInteractionController(this.iD)
+ return field
+ }
+ private set
+
+ @Transient
+ var remoteStatusInteractionController: StatusInteractionController? = null
+ get() {
+ if (field == null) field = StatusInteractionController(this.iD, false)
+ return field
+ }
+ private set
+
+ @Transient
+ var cacheController: CacheController? = null
+ get() {
+ if (field == null) field = CacheController(this.iD)
+ return field
+ }
+ private set
+
+ @Transient
+ var pushSubscriptionManager: PushSubscriptionManager? = null
+ get() {
+ if (field == null) field = PushSubscriptionManager(this.iD)
+ return field
+ }
+ private set
+
+ @Transient
+ private var prefs: SharedPreferences? = null
+
+ @Transient
+ private var preferencesNeedSaving = false
+
+ @Transient
+ var localPreferences: AccountLocalPreferences? = null
+ get() {
+ if (field == null) field = AccountLocalPreferences(this.rawLocalPreferences, this)
+ return field
+ }
+ private set
+
+ internal constructor(
+ token: Token,
+ self: Account,
+ app: Application,
+ domain: String?,
+ activated: Boolean,
+ activationInfo: AccountActivationInfo?
+ ) {
+ this.token = token
+ this.self = self
+ this.domain = domain
+ this.app = app
+ this.activated = activated
+ this.activationInfo = activationInfo
+ infoLastUpdated = System.currentTimeMillis()
+ }
+
+ internal constructor()
+
+ val iD: String
+ get() = domain + "_" + self?.id
+
+ val fullUsername: String
+ get() = '@'.toString() + self?.username + '@' + domain
+
+ fun preferencesFromAccountSource(account: Account?) {
+ if (account != null && account.source != null && preferences != null) {
+ if (account.source.privacy != null) preferences!!.postingDefaultVisibility =
+ account.source.privacy
+ if (account.source.language != null) preferences!!.postingDefaultLanguage =
+ account.source.language
+ }
+ }
+
+ fun reloadPreferences(callback: Consumer<Preferences>?) {
+ GetPreferences()
+ .setCallback(object : Callback<Preferences> {
+ override fun onSuccess(result: Preferences) {
+ preferences = result
+ preferencesFromAccountSource(self)
+ callback?.accept(result)
+ AccountSessionManager.getInstance().writeAccountsFile()
+ }
+
+ override fun onError(error: ErrorResponse) {
+ Log.w(TAG, "Failed to load preferences for account $iD: $error")
+ if (preferences == null) preferences = Preferences()
+ preferencesFromAccountSource(self)
+ }
+ })
+ .exec(this.iD)
+ }
+
+ val rawLocalPreferences: SharedPreferences?
+ get() {
+ if (prefs == null) prefs = MastodonApp.context.getSharedPreferences(
+ this.iD,
+ Context.MODE_PRIVATE
+ )
+ return prefs
+ }
+
+ fun reloadNotificationsMarker(callback: Consumer<String?>) {
+ GetMarkers()
+ .setCallback(object : Callback<TimelineMarkers> {
+ override fun onSuccess(result: TimelineMarkers) {
+ if (result.notifications != null && !TextUtils.isEmpty(result.notifications.lastReadId)) {
+ var id = result.notifications.lastReadId
+ val lastKnown: String? = lastKnownNotificationsMarker
+ if (ObjectIdComparator.INSTANCE.compare(id, lastKnown) < 0) {
+ // Marker moved back -- previous marker update must have failed.
+ // Pretend it didn't happen and repeat the request.
+ id = lastKnown
+ SaveMarkers(null, id).exec(iD)
+ }
+ callback.accept(id)
+ setNotificationsMarker(id, false)
+ }
+ }
+
+ override fun onError(error: ErrorResponse?) {}
+ })
+ .exec(this.iD)
+ }
+
+ fun setNotificationsMarker(id: String?, clearUnread: Boolean) {
+ this.rawLocalPreferences?.edit()?.putString("notificationsMarker", id)?.apply()
+ E.post(NotificationsMarkerUpdatedEvent(this.iD, id, clearUnread))
+ }
+
+ fun logOut(activity: Activity?, onDone: Runnable) {
+ RevokeOauthToken(app?.clientId, app?.clientSecret, token?.accessToken)
+ .setCallback(object : Callback<Any?> {
+ override fun onSuccess(result: Any?) {
+ AccountSessionManager.getInstance().removeAccount(iD)
+ onDone.run()
+ }
+
+ override fun onError(error: ErrorResponse?) {
+ AccountSessionManager.getInstance().removeAccount(iD)
+ onDone.run()
+ }
+ })
+ .wrapProgress(activity, R.string.loading, false)
+ .exec(this.iD)
+ }
+
+ fun savePreferencesLater() {
+ preferencesNeedSaving = true
+ }
+
+ fun savePreferencesIfPending() {
+ if (preferencesNeedSaving) {
+ UpdateAccountCredentialsPreferences(
+ preferences,
+ self?.locked,
+ self?.discoverable,
+ self?.source?.indexable
+ )
+ .setCallback(object : Callback<Account?> {
+ override fun onSuccess(result: Account?) {
+ preferencesNeedSaving = false
+ self = result
+ AccountSessionManager.getInstance().writeAccountsFile()
+ }
+
+ override fun onError(error: ErrorResponse?) {
+ Log.e(TAG, "failed to save preferences: $error")
+ }
+ })
+ .exec(this.iD)
+ }
+ }
+
+ @JvmOverloads
+ fun filterStatuses(
+ statuses: MutableList<Status?>,
+ context: FilterContext?,
+ profile: Account? = null
+ ) {
+ filterStatusContainingObjects<Status?>(
+ statuses,
+ Function.identity<Status?>(),
+ context,
+ profile
+ )
+ }
+
+ fun <T> filterStatusContainingObjects(
+ objects: MutableList<T?>,
+ extractor: Function<T?, Status?>,
+ context: FilterContext?
+ ) {
+ filterStatusContainingObjects<T?>(objects, extractor, context, null)
+ }
+
+ private fun statusIsOnOwnProfile(s: Status, profile: Account?): Boolean {
+ return self != null && profile != null && s.account != null && self!!.id == profile.id && self!!.id == s.account.id
+ }
+
+ private fun isFilteredType(s: Status): Boolean {
+ val localPreferences = this.localPreferences!!
+ return (!localPreferences.showReplies && s.inReplyToId != null)
+ || (!localPreferences.showBoosts && s.reblog != null)
+ }
+
+ fun <T> filterStatusContainingObjects(
+ objects: MutableList<T?>,
+ extractor: Function<T?, Status?>,
+ context: FilterContext?,
+ profile: Account?
+ ) {
+ val localPreferences = this.localPreferences!!
+ if (!localPreferences.serverSideFiltersSupported) for (obj in objects) {
+ val s = extractor.apply(obj)
+ if (s != null && s.filtered != null) {
+ localPreferences.serverSideFiltersSupported = true
+ localPreferences.save()
+ break
+ }
+ }
+
+ val removeUs: MutableList<T?> = ArrayList()
+ for (i in objects.indices) {
+ val o = objects[i]
+ if (filterStatusContainingObject<T?>(o, extractor, context, profile)) {
+ val s = extractor.apply(o)
+ removeUs.add(o)
+ if (s != null && s.hasGapAfter != null && i > 0) {
+ // oops, we're about to remove an item that has a gap after...
+ // gotta find the previous status that's not also about to be removed
+ for (j in i - 1 downTo 0) {
+ val p = objects[j]
+ val prev = extractor.apply(objects[j])
+ if (prev != null && !removeUs.contains(p)) {
+ prev.hasGapAfter = s.hasGapAfter
+ break
+ }
+ }
+ }
+ }
+ }
+ objects.removeAll(removeUs)
+ }
+
+ fun <T> filterStatusContainingObject(
+ `object`: T?,
+ extractor: Function<T?, Status?>,
+ context: FilterContext?,
+ profile: Account?
+ ): Boolean {
+ val s = extractor.apply(`object`) ?: return false
+ // don't hide own posts in own profile
+ if (statusIsOnOwnProfile(s, profile)) return false
+ if (isFilteredType(s) && (context == FilterContext.HOME || context == FilterContext.PUBLIC)) return true
+ // Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
+ if (this.localPreferences!!.serverSideFiltersSupported) {
+ // Moshidon: this code path in CustomLocalTimelines makes the app crash, so this check is here
+ if (s.filtered == null) return false
+ for (filter in s.filtered) {
+ if (filter.filter.isActive && filter.filter.filterAction == FilterAction.HIDE && filter.filter.context.contains(
+ context
+ )
+ ) return true
+ }
+ } else if (wordFilters != null) {
+ for (filter in wordFilters) {
+ if (filter.context.contains(context) && filter.matches(s) && filter.isActive) return true
+ }
+ }
+ return false
+ }
+
+ fun getClientSideFilters(status: Status): MutableList<FilterResult?> {
+ val filters: MutableList<FilterResult?> = ArrayList()
+
+ // filter post that have no alt text
+ // it only applies when activated in the settings
+ val altTextFilter = AltTextFilter(
+ FilterAction.WARN,
+ EnumSet.allOf(FilterContext::class.java)
+ )
+ if (altTextFilter.matches(status)) {
+ val filterResult = FilterResult()
+ filterResult.filter = altTextFilter
+ filterResult.keywordMatches = mutableListOf<String?>()
+ filters.add(filterResult)
+ }
+ return filters
+ }
+
+ fun updateAccountInfo() {
+ AccountSessionManager.getInstance().updateSessionLocalInfo(this)
+ }
+
+ val instance: Optional<Instance>
+ get() = Optional.ofNullable<Instance>(
+ AccountSessionManager.getInstance().getInstanceInfo(domain)
+ )
+
+ val instanceUri: Uri?
+ get() = Uri.Builder()
+ .scheme("https")
+ .authority(
+ this.instance.map(Function { i: Instance -> i.normalizedUri })
+ .orElse(domain)
+ )
+ .build()
+
+ val defaultAvatarUrl: String
+ get() = this.instance
+ .map(Function { instance: Instance -> "https://" + domain + (if (instance.isAkkoma) "/images/avi.png" else "/avatars/original/missing.png") })
+ .orElse("")
+
+ var isNotificationsMentionsOnly: Boolean
+ get() = this.rawLocalPreferences!!.getBoolean("notificationsMentionsOnly", false)
+ set(mentionsOnly) {
+ this.rawLocalPreferences!!.edit().putBoolean("notificationsMentionsOnly", mentionsOnly)
+ .apply()
+ }
+
+ companion object {
+ private const val TAG = "AccountSession"
+ }
+}