New settings (#891)
* change drawer items * rename SettingsActivity * introduce AccountSettings activity * improve account settings, move notification settings * sync settings with server * rename settings back to preferences * add functionality for settings * move mediaPreviewEnabled preference to AccountPreferences * replace shared prefs with accountmanager * move PreferencesFragment to support library * split preferences fragment into smaller fragments, merge AccountPreferencesActivity into PreferencesFragment * adjust icon size, add icons to general preferences * change mediaPreviewEnabled and alwaysShowSensitiveMedia pref position * add database migration * remove pullNotificationCheckInterval option * fix preference in TimelineFragment * Update Chinese translations. (#915) * Update zh-CN translations. * Update zh-SG translations. * Update zh-TW translations. * Update zh-MO translations. * Update zh-HK translations. * Fix errors in zh-CN translations. * Fix errors in zh-SG translations. * Fix errors in zh-TW translations. * Fix errors in zh-MO translations. * Fix errors in zh-HK translations.
This commit is contained in:
parent
690e612f8b
commit
348c20c792
65 changed files with 1636 additions and 1083 deletions
|
@ -52,7 +52,7 @@ public final class AccountListActivity extends BaseActivity implements HasSuppor
|
|||
return intent;
|
||||
}
|
||||
|
||||
enum Type {
|
||||
public enum Type {
|
||||
BLOCKS,
|
||||
MUTES,
|
||||
FOLLOW_REQUESTS,
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
package com.keylesspalace.tusky;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
|
@ -32,8 +31,6 @@ import android.util.TypedValue;
|
|||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
|
||||
import com.evernote.android.job.JobManager;
|
||||
import com.evernote.android.job.JobRequest;
|
||||
import com.keylesspalace.tusky.db.AccountEntity;
|
||||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
import com.keylesspalace.tusky.di.Injectable;
|
||||
|
@ -122,10 +119,6 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
|
|||
super.finish();
|
||||
}
|
||||
|
||||
protected SharedPreferences getPrivatePreferences() {
|
||||
return getSharedPreferences(getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
protected void redirectIfNotLoggedIn() {
|
||||
AccountEntity account = accountManager.getActiveAccount();
|
||||
if (account == null) {
|
||||
|
@ -154,34 +147,6 @@ public abstract class BaseActivity extends AppCompatActivity implements Injectab
|
|||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
protected void enablePushNotifications() {
|
||||
// schedule job to pull notifications
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String minutesString = preferences.getString("pullNotificationCheckInterval", "15");
|
||||
long minutes = Long.valueOf(minutesString);
|
||||
if (minutes < 15) {
|
||||
preferences.edit().putString("pullNotificationCheckInterval", "15").apply();
|
||||
minutes = 15;
|
||||
}
|
||||
setPullNotificationCheckInterval(minutes);
|
||||
}
|
||||
|
||||
protected void disablePushNotifications() {
|
||||
// Cancel the repeating call for "pull" notifications.
|
||||
JobManager.instance().cancelAllForTag(NotificationPullJobCreator.NOTIFICATIONS_JOB_TAG);
|
||||
}
|
||||
|
||||
protected void setPullNotificationCheckInterval(long minutes) {
|
||||
long checkInterval = 1000 * 60 * minutes;
|
||||
|
||||
new JobRequest.Builder(NotificationPullJobCreator.NOTIFICATIONS_JOB_TAG)
|
||||
.setPeriodic(checkInterval)
|
||||
.setUpdateCurrent(true)
|
||||
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
|
||||
.build()
|
||||
.scheduleAsync();
|
||||
}
|
||||
|
||||
protected void showErrorDialog(View anyView, @StringRes int descriptionId, @StringRes int actionId, View.OnClickListener listener) {
|
||||
if (anyView != null) {
|
||||
Snackbar bar = Snackbar.make(anyView, getString(descriptionId), Snackbar.LENGTH_SHORT);
|
||||
|
|
|
@ -390,7 +390,7 @@ public final class ComposeActivity
|
|||
}
|
||||
photoUploadUri = savedInstanceState.getParcelable("photoUploadUri");
|
||||
} else {
|
||||
statusMarkSensitive = false;
|
||||
statusMarkSensitive = activeAccount.getDefaultMediaSensitivity();
|
||||
startingHideText = false;
|
||||
photoUploadUri = null;
|
||||
}
|
||||
|
@ -406,9 +406,7 @@ public final class ComposeActivity
|
|||
if (intent != null) {
|
||||
|
||||
if (startingVisibility == Status.Visibility.UNKNOWN) {
|
||||
Status.Visibility preferredVisibility = Status.Visibility.byString(
|
||||
preferences.getString("defaultPostPrivacy",
|
||||
Status.Visibility.PUBLIC.serverString()));
|
||||
Status.Visibility preferredVisibility = activeAccount.getDefaultPostPrivacy();
|
||||
Status.Visibility replyVisibility = Status.Visibility.byNum(
|
||||
intent.getIntExtra(REPLY_VISIBILITY_EXTRA, Status.Visibility.UNKNOWN.getNum()));
|
||||
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
package com.keylesspalace.tusky;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.preference.DialogPreference;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
|
@ -25,9 +27,8 @@ import java.util.ArrayList;
|
|||
/**
|
||||
* This Preference lets the user select their preferred emoji font
|
||||
*/
|
||||
public class EmojiPreference extends DialogPreference {
|
||||
public class EmojiPreference extends Preference {
|
||||
private static final String TAG = "EmojiPreference";
|
||||
private final Context context;
|
||||
private EmojiCompatFont selected, original;
|
||||
static final String FONT_PREFERENCE = "selected_emoji_font";
|
||||
private static final EmojiCompatFont[] FONTS = EmojiCompatFont.FONTS;
|
||||
|
@ -42,13 +43,6 @@ public class EmojiPreference extends DialogPreference {
|
|||
|
||||
public EmojiPreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this.context = context;
|
||||
|
||||
setDialogLayoutResource(R.layout.dialog_emojicompat);
|
||||
|
||||
setPositiveButtonText(android.R.string.ok);
|
||||
setNegativeButtonText(android.R.string.cancel);
|
||||
setDialogIcon(null);
|
||||
|
||||
// Find out which font is currently active
|
||||
this.selected = EmojiCompatFont.byId(PreferenceManager
|
||||
|
@ -60,27 +54,31 @@ public class EmojiPreference extends DialogPreference {
|
|||
setSummary(selected.getDisplay(context));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void onBindDialogView(View view) {
|
||||
super.onBindDialogView(view);
|
||||
protected void onClick() {
|
||||
|
||||
View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_emojicompat, null);
|
||||
|
||||
for(int i = 0; i < viewIds.length; i++) {
|
||||
setupItem(view.findViewById(viewIds[i]), FONTS[i]);
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setView(view)
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> onDialogOk())
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void setupItem(View container, EmojiCompatFont font) {
|
||||
Context context = container.getContext();
|
||||
|
||||
TextView title = container.findViewById(R.id.emojicompat_name);
|
||||
TextView caption = container.findViewById(R.id.emojicompat_caption);
|
||||
ImageView thumb = container.findViewById(R.id.emojicompat_thumb);
|
||||
ImageButton download = container.findViewById(R.id.emojicompat_download);
|
||||
|
||||
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
|
||||
|
||||
RadioButton radio = container.findViewById(R.id.emojicompat_radio);
|
||||
TextView title = container.findViewById(R.id.emojicompat_name);
|
||||
TextView caption = container.findViewById(R.id.emojicompat_caption);
|
||||
ImageView thumb = container.findViewById(R.id.emojicompat_thumb);
|
||||
ImageButton download = container.findViewById(R.id.emojicompat_download);
|
||||
ImageButton cancel = container.findViewById(R.id.emojicompat_download_cancel);
|
||||
RadioButton radio = container.findViewById(R.id.emojicompat_radio);
|
||||
|
||||
// Initialize all the views
|
||||
title.setText(font.getDisplay(context));
|
||||
|
@ -122,7 +120,7 @@ public class EmojiPreference extends DialogPreference {
|
|||
cancel.setVisibility(View.VISIBLE);
|
||||
|
||||
|
||||
font.downloadFont(context, new EmojiCompatFont.Downloader.EmojiDownloadListener() {
|
||||
font.downloadFont(getContext(), new EmojiCompatFont.Downloader.EmojiDownloadListener() {
|
||||
@Override
|
||||
public void onDownloaded(EmojiCompatFont font) {
|
||||
finishDownload(font, container);
|
||||
|
@ -194,7 +192,7 @@ public class EmojiPreference extends DialogPreference {
|
|||
cancel.setVisibility(View.GONE);
|
||||
caption.setVisibility(View.VISIBLE);
|
||||
|
||||
if(font.isDownloaded(context)) {
|
||||
if(font.isDownloaded(getContext())) {
|
||||
// Make it selectable
|
||||
download.setVisibility(View.GONE);
|
||||
radio.setVisibility(View.VISIBLE);
|
||||
|
@ -225,7 +223,7 @@ public class EmojiPreference extends DialogPreference {
|
|||
Log.i(TAG, "saveSelectedFont: Font ID: " + index);
|
||||
// It's saved using the key FONT_PREFERENCE
|
||||
PreferenceManager
|
||||
.getDefaultSharedPreferences(context)
|
||||
.getDefaultSharedPreferences(getContext())
|
||||
.edit()
|
||||
.putInt(FONT_PREFERENCE, index)
|
||||
.apply();
|
||||
|
@ -235,29 +233,26 @@ public class EmojiPreference extends DialogPreference {
|
|||
/**
|
||||
* That's it. The user doesn't want to switch between these amazing radio buttons anymore!
|
||||
* That means, the selected font can be saved (if the user hit OK)
|
||||
* @param positiveResult if OK has been selected.
|
||||
*/
|
||||
@Override
|
||||
public void onDialogClosed(boolean positiveResult) {
|
||||
if(positiveResult) {
|
||||
private void onDialogOk() {
|
||||
saveSelectedFont();
|
||||
if(selected != original) {
|
||||
new AlertDialog.Builder(context)
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(R.string.restart_required)
|
||||
.setMessage(R.string.restart_emoji)
|
||||
.setNegativeButton(R.string.later, null)
|
||||
.setPositiveButton(R.string.restart, ((dialog, which) -> {
|
||||
// Restart the app
|
||||
// From https://stackoverflow.com/a/17166729/5070653
|
||||
Intent launchIntent = new Intent(context, MainActivity.class);
|
||||
Intent launchIntent = new Intent(getContext(), SplashActivity.class);
|
||||
PendingIntent mPendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
getContext(),
|
||||
// This is the codepoint of the party face emoji :D
|
||||
0x1f973,
|
||||
launchIntent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
AlarmManager mgr =
|
||||
(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
(AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
|
||||
if (mgr != null) {
|
||||
mgr.set(
|
||||
AlarmManager.RTC,
|
||||
|
@ -267,11 +262,7 @@ public class EmojiPreference extends DialogPreference {
|
|||
System.exit(0);
|
||||
})).show();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This line is needed in order to reset the radio buttons later
|
||||
selected = original;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@ import android.support.annotation.NonNull;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.TabLayout;
|
||||
import android.support.graphics.drawable.VectorDrawableCompat;
|
||||
import android.support.text.emoji.EmojiCompat;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
@ -85,15 +84,14 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
|||
private static final long DRAWER_ITEM_ADD_ACCOUNT = -13;
|
||||
private static final long DRAWER_ITEM_EDIT_PROFILE = 0;
|
||||
private static final long DRAWER_ITEM_FAVOURITES = 1;
|
||||
private static final long DRAWER_ITEM_MUTED_USERS = 2;
|
||||
private static final long DRAWER_ITEM_BLOCKED_USERS = 3;
|
||||
private static final long DRAWER_ITEM_SEARCH = 4;
|
||||
private static final long DRAWER_ITEM_PREFERENCES = 5;
|
||||
private static final long DRAWER_ITEM_ABOUT = 6;
|
||||
private static final long DRAWER_ITEM_LOG_OUT = 7;
|
||||
private static final long DRAWER_ITEM_FOLLOW_REQUESTS = 8;
|
||||
private static final long DRAWER_ITEM_SAVED_TOOT = 9;
|
||||
private static final long DRAWER_ITEM_LISTS = 10;
|
||||
private static final long DRAWER_ITEM_LISTS = 2;
|
||||
private static final long DRAWER_ITEM_SEARCH = 3;
|
||||
private static final long DRAWER_ITEM_SAVED_TOOT = 4;
|
||||
private static final long DRAWER_ITEM_ACCOUNT_SETTINGS = 5;
|
||||
private static final long DRAWER_ITEM_SETTINGS = 6;
|
||||
private static final long DRAWER_ITEM_ABOUT = 7;
|
||||
private static final long DRAWER_ITEM_LOG_OUT = 8;
|
||||
private static final long DRAWER_ITEM_FOLLOW_REQUESTS = 9;
|
||||
|
||||
@Inject
|
||||
public DispatchingAndroidInjector<Fragment> fragmentInjector;
|
||||
|
@ -215,9 +213,9 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
|||
|
||||
// Setup push notifications
|
||||
if (NotificationHelper.areNotificationsEnabled(this, accountManager)) {
|
||||
enablePushNotifications();
|
||||
NotificationHelper.enablePullNotifications();
|
||||
} else {
|
||||
disablePushNotifications();
|
||||
NotificationHelper.disablePullNotifications();
|
||||
}
|
||||
|
||||
eventHub.getEvents()
|
||||
|
@ -311,22 +309,17 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
|||
}
|
||||
});
|
||||
|
||||
VectorDrawableCompat muteDrawable = VectorDrawableCompat.create(getResources(),
|
||||
R.drawable.ic_mute_24dp, getTheme());
|
||||
ThemeUtils.setDrawableTint(this, muteDrawable, R.attr.toolbar_icon_tint);
|
||||
|
||||
List<IDrawerItem> listItems = new ArrayList<>(11);
|
||||
List<IDrawerItem> listItems = new ArrayList<>(10);
|
||||
listItems.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_EDIT_PROFILE).withName(R.string.action_edit_profile).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_person));
|
||||
listItems.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_FAVOURITES).withName(R.string.action_view_favourites).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_star));
|
||||
listItems.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_LISTS).withName(R.string.action_lists).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_list));
|
||||
listItems.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_MUTED_USERS).withName(R.string.action_view_mutes).withSelectable(false).withIcon(muteDrawable));
|
||||
listItems.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_BLOCKED_USERS).withName(R.string.action_view_blocks).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_block));
|
||||
listItems.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_SEARCH).withName(R.string.action_search).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_search));
|
||||
listItems.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_SAVED_TOOT).withName(R.string.action_access_saved_toot).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_save));
|
||||
listItems.add(new PrimaryDrawerItem().withIdentifier(DRAWER_ITEM_SAVED_TOOT).withName(R.string.action_access_saved_toot).withSelectable(false).withIcon(R.drawable.ic_notebook).withIconTintingEnabled(true));
|
||||
listItems.add(new DividerDrawerItem());
|
||||
listItems.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_PREFERENCES).withName(R.string.action_view_preferences).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_settings));
|
||||
listItems.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_ACCOUNT_SETTINGS).withName(R.string.action_view_account_preferences).withSelectable(false).withIcon(R.drawable.ic_account_settings).withIconTintingEnabled(true));
|
||||
listItems.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_SETTINGS).withName(R.string.action_view_preferences).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_settings));
|
||||
listItems.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_ABOUT).withName(R.string.about_title_activity).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_info));
|
||||
listItems.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_LOG_OUT).withName(R.string.action_logout).withSelectable(false).withIcon(GoogleMaterial.Icon.gmd_exit_to_app));
|
||||
listItems.add(new SecondaryDrawerItem().withIdentifier(DRAWER_ITEM_LOG_OUT).withName(R.string.action_logout).withSelectable(false).withIcon(R.drawable.ic_logout).withIconTintingEnabled(true));
|
||||
|
||||
drawer = new DrawerBuilder()
|
||||
.withActivity(this)
|
||||
|
@ -344,19 +337,14 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
|||
} else if (drawerItemIdentifier == DRAWER_ITEM_FAVOURITES) {
|
||||
Intent intent = new Intent(MainActivity.this, FavouritesActivity.class);
|
||||
startActivityWithSlideInAnimation(intent);
|
||||
} else if (drawerItemIdentifier == DRAWER_ITEM_MUTED_USERS) {
|
||||
Intent intent = new Intent(MainActivity.this, AccountListActivity.class);
|
||||
intent.putExtra("type", AccountListActivity.Type.MUTES);
|
||||
startActivityWithSlideInAnimation(intent);
|
||||
} else if (drawerItemIdentifier == DRAWER_ITEM_BLOCKED_USERS) {
|
||||
Intent intent = new Intent(MainActivity.this, AccountListActivity.class);
|
||||
intent.putExtra("type", AccountListActivity.Type.BLOCKS);
|
||||
startActivityWithSlideInAnimation(intent);
|
||||
} else if (drawerItemIdentifier == DRAWER_ITEM_SEARCH) {
|
||||
Intent intent = new Intent(MainActivity.this, SearchActivity.class);
|
||||
startActivityWithSlideInAnimation(intent);
|
||||
} else if (drawerItemIdentifier == DRAWER_ITEM_PREFERENCES) {
|
||||
Intent intent = new Intent(MainActivity.this, PreferencesActivity.class);
|
||||
} else if (drawerItemIdentifier == DRAWER_ITEM_ACCOUNT_SETTINGS) {
|
||||
Intent intent = PreferencesActivity.newIntent(MainActivity.this, PreferencesActivity.ACCOUNT_PREFERENCES);
|
||||
startActivityWithSlideInAnimation(intent);
|
||||
} else if (drawerItemIdentifier == DRAWER_ITEM_SETTINGS) {
|
||||
Intent intent = PreferencesActivity.newIntent(MainActivity.this, PreferencesActivity.GENERAL_PREFERENCES);
|
||||
startActivityWithSlideInAnimation(intent);
|
||||
} else if (drawerItemIdentifier == DRAWER_ITEM_ABOUT) {
|
||||
Intent intent = new Intent(MainActivity.this, AboutActivity.class);
|
||||
|
@ -444,8 +432,9 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
|||
|
||||
AccountEntity newAccount = accountManager.logActiveAccountOut();
|
||||
|
||||
if (!NotificationHelper.areNotificationsEnabled(MainActivity.this, accountManager))
|
||||
disablePushNotifications();
|
||||
if (!NotificationHelper.areNotificationsEnabled(MainActivity.this, accountManager)) {
|
||||
NotificationHelper.disablePullNotifications();
|
||||
}
|
||||
|
||||
Intent intent;
|
||||
if (newAccount == null) {
|
||||
|
|
|
@ -1,180 +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;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.annotation.XmlRes;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.keylesspalace.tusky.fragment.PreferencesFragment;
|
||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
||||
|
||||
public class PreferencesActivity extends BaseActivity
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private boolean restartActivitiesOnExit;
|
||||
private @XmlRes int currentPreferences;
|
||||
private @StringRes int currentTitle;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (savedInstanceState != null) {
|
||||
restartActivitiesOnExit = savedInstanceState.getBoolean("restart");
|
||||
} else {
|
||||
Bundle extras = getIntent().getExtras();
|
||||
restartActivitiesOnExit = extras != null && extras.getBoolean("restart");
|
||||
}
|
||||
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
setContentView(R.layout.activity_preferences);
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setDisplayShowHomeEnabled(true);
|
||||
}
|
||||
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
currentPreferences = R.xml.preferences;
|
||||
currentTitle = R.string.action_view_preferences;
|
||||
} else {
|
||||
currentPreferences = savedInstanceState.getInt("preferences");
|
||||
currentTitle = savedInstanceState.getInt("title");
|
||||
}
|
||||
showFragment(currentPreferences, currentTitle);
|
||||
|
||||
}
|
||||
|
||||
public void showFragment(@XmlRes int preferenceId, @StringRes int title) {
|
||||
|
||||
//TODO: cache the Fragments so they can be reused
|
||||
getFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragment_container, PreferencesFragment.newInstance(preferenceId))
|
||||
.commit();
|
||||
|
||||
getFragmentManager().executePendingTransactions();
|
||||
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setTitle(title);
|
||||
}
|
||||
|
||||
currentPreferences = preferenceId;
|
||||
currentTitle = title;
|
||||
}
|
||||
|
||||
private void saveInstanceState(Bundle outState) {
|
||||
outState.putBoolean("restart", restartActivitiesOnExit);
|
||||
outState.putInt("preferences", currentPreferences);
|
||||
outState.putInt("title", currentTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
saveInstanceState(outState);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
switch (key) {
|
||||
case "appTheme": {
|
||||
String theme = sharedPreferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT);
|
||||
Log.d("activeTheme", theme);
|
||||
ThemeUtils.setAppNightMode(theme, this);
|
||||
restartActivitiesOnExit = true;
|
||||
|
||||
// recreate() could be used instead, but it doesn't have an animation B).
|
||||
Intent intent = getIntent();
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
Bundle savedInstanceState = new Bundle();
|
||||
saveInstanceState(savedInstanceState);
|
||||
intent.putExtras(savedInstanceState);
|
||||
startActivityWithSlideInAnimation(intent);
|
||||
finish();
|
||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
||||
}
|
||||
case "statusTextSize": {
|
||||
restartActivitiesOnExit = true;
|
||||
break;
|
||||
}
|
||||
case "absoluteTimeView": {
|
||||
restartActivitiesOnExit = true;
|
||||
break;
|
||||
}
|
||||
case "notificationsEnabled": {
|
||||
boolean enabled = sharedPreferences.getBoolean("notificationsEnabled", true);
|
||||
if (enabled) {
|
||||
enablePushNotifications();
|
||||
} else {
|
||||
disablePushNotifications();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "pullNotificationCheckInterval": {
|
||||
String s = sharedPreferences.getString("pullNotificationCheckInterval", "15");
|
||||
long minutes = Long.valueOf(s);
|
||||
setPullNotificationCheckInterval(minutes);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
//if we are not on the top level, show the top level. Else exit the activity
|
||||
if (currentPreferences != R.xml.preferences) {
|
||||
showFragment(R.xml.preferences, R.string.action_view_preferences);
|
||||
|
||||
} else {
|
||||
/* Switching themes won't actually change the theme of activities on the back stack.
|
||||
* Either the back stack activities need to all be recreated, or do the easier thing, which
|
||||
* is hijack the back button press and use it to launch a new MainActivity and clear the
|
||||
* back stack. */
|
||||
if (restartActivitiesOnExit) {
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
startActivityWithSlideInAnimation(intent);
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home: {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
186
app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt
Normal file
186
app/src/main/java/com/keylesspalace/tusky/PreferencesActivity.kt
Normal file
|
@ -0,0 +1,186 @@
|
|||
/* Copyright 2018 Conny Duck
|
||||
*
|
||||
* 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
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.preference.PreferenceManager
|
||||
import android.support.v4.app.Fragment
|
||||
import android.util.Log
|
||||
import android.view.MenuItem
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
||||
import com.keylesspalace.tusky.fragment.preference.*
|
||||
import com.keylesspalace.tusky.util.ThemeUtils
|
||||
import com.keylesspalace.tusky.util.getNonNullString
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.DispatchingAndroidInjector
|
||||
import dagger.android.support.HasSupportFragmentInjector
|
||||
import kotlinx.android.synthetic.main.toolbar_basic.*
|
||||
import java.lang.IllegalArgumentException
|
||||
import javax.inject.Inject
|
||||
|
||||
class PreferencesActivity : BaseActivity(), SharedPreferences.OnSharedPreferenceChangeListener, HasSupportFragmentInjector {
|
||||
|
||||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
@Inject
|
||||
lateinit var fragmentInjector: DispatchingAndroidInjector<Fragment>
|
||||
|
||||
private var restartActivitiesOnExit: Boolean = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setContentView(R.layout.activity_preferences)
|
||||
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar?.run {
|
||||
setDisplayHomeAsUpEnabled(true)
|
||||
setDisplayShowHomeEnabled(true)
|
||||
}
|
||||
|
||||
val fragment: Fragment = when(intent.getIntExtra(EXTRA_PREFERENCE_TYPE, 0)) {
|
||||
GENERAL_PREFERENCES -> {
|
||||
setTitle(R.string.action_view_preferences)
|
||||
PreferencesFragment.newInstance()
|
||||
}
|
||||
ACCOUNT_PREFERENCES -> {
|
||||
setTitle(R.string.action_view_account_preferences)
|
||||
AccountPreferencesFragment.newInstance()
|
||||
}
|
||||
NOTIFICATION_PREFERENCES -> {
|
||||
setTitle(R.string.pref_title_edit_notification_settings)
|
||||
NotificationPreferencesFragment.newInstance()
|
||||
}
|
||||
TAB_FILTER_PREFERENCES -> {
|
||||
setTitle(R.string.pref_title_status_tabs)
|
||||
TabFilterPreferencesFragment.newInstance()
|
||||
}
|
||||
PROXY_PREFERENCES -> {
|
||||
setTitle(R.string.pref_title_http_proxy_settings)
|
||||
ProxyPreferencesFragment.newInstance()
|
||||
}
|
||||
else -> throw IllegalArgumentException("preferenceType not known")
|
||||
}
|
||||
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.fragment_container, fragment)
|
||||
.commit()
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
onBackPressed()
|
||||
return true
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
private fun saveInstanceState(outState: Bundle) {
|
||||
outState.putBoolean("restart", restartActivitiesOnExit)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putBoolean("restart", restartActivitiesOnExit)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
when (key) {
|
||||
"appTheme" -> {
|
||||
val theme = sharedPreferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT)
|
||||
Log.d("activeTheme", theme)
|
||||
ThemeUtils.setAppNightMode(theme!!, this)
|
||||
restartActivitiesOnExit = true
|
||||
|
||||
// recreate() could be used instead, but it doesn't have an animation B).
|
||||
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
val savedInstanceState = Bundle()
|
||||
saveInstanceState(savedInstanceState)
|
||||
intent.putExtras(savedInstanceState)
|
||||
startActivityWithSlideInAnimation(intent)
|
||||
finish()
|
||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out)
|
||||
|
||||
restartActivitiesOnExit = true
|
||||
|
||||
}
|
||||
"statusTextSize" -> {
|
||||
restartActivitiesOnExit = true
|
||||
}
|
||||
"absoluteTimeView" -> {
|
||||
restartActivitiesOnExit = true
|
||||
}
|
||||
}
|
||||
|
||||
eventHub.dispatch(PreferenceChangedEvent(key))
|
||||
}
|
||||
|
||||
|
||||
override fun onBackPressed() {
|
||||
/* Switching themes won't actually change the theme of activities on the back stack.
|
||||
* Either the back stack activities need to all be recreated, or do the easier thing, which
|
||||
* is hijack the back button press and use it to launch a new MainActivity and clear the
|
||||
* back stack. */
|
||||
if (restartActivitiesOnExit) {
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
startActivityWithSlideInAnimation(intent)
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun supportFragmentInjector(): AndroidInjector<Fragment> {
|
||||
return fragmentInjector
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val GENERAL_PREFERENCES = 0
|
||||
const val ACCOUNT_PREFERENCES = 1
|
||||
const val NOTIFICATION_PREFERENCES = 2
|
||||
const val TAB_FILTER_PREFERENCES = 3
|
||||
const val PROXY_PREFERENCES = 4
|
||||
private const val EXTRA_PREFERENCE_TYPE = "EXTRA_PREFERENCE_TYPE"
|
||||
|
||||
@JvmStatic
|
||||
fun newIntent(context: Context, preferenceType: Int): Intent {
|
||||
val intent = Intent(context, PreferencesActivity::class.java)
|
||||
intent.putExtra(EXTRA_PREFERENCE_TYPE, preferenceType)
|
||||
return intent
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,9 +20,7 @@ import android.app.Application;
|
|||
import android.app.Service;
|
||||
import android.arch.persistence.room.Room;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.text.emoji.EmojiCompat;
|
||||
|
||||
import com.evernote.android.job.JobManager;
|
||||
|
@ -31,6 +29,7 @@ import com.keylesspalace.tusky.db.AccountManager;
|
|||
import com.keylesspalace.tusky.db.AppDatabase;
|
||||
import com.keylesspalace.tusky.di.AppInjector;
|
||||
import com.keylesspalace.tusky.util.EmojiCompatFont;
|
||||
import com.keylesspalace.tusky.util.NotificationPullJobCreator;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -59,10 +58,6 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
|||
|
||||
private ServiceLocator serviceLocator;
|
||||
|
||||
public static TuskyApplication getInstance(@NonNull Context context) {
|
||||
return (TuskyApplication) context.getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
@ -70,7 +65,8 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
|||
appDatabase = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tuskyDB")
|
||||
.allowMainThreadQueries()
|
||||
.addMigrations(AppDatabase.MIGRATION_2_3, AppDatabase.MIGRATION_3_4, AppDatabase.MIGRATION_4_5,
|
||||
AppDatabase.MIGRATION_5_6, AppDatabase.MIGRATION_6_7, AppDatabase.MIGRATION_7_8, AppDatabase.MIGRATION_8_9)
|
||||
AppDatabase.MIGRATION_5_6, AppDatabase.MIGRATION_6_7, AppDatabase.MIGRATION_7_8,
|
||||
AppDatabase.MIGRATION_8_9, AppDatabase.MIGRATION_9_10)
|
||||
.build();
|
||||
accountManager = new AccountManager(appDatabase);
|
||||
serviceLocator = new ServiceLocator() {
|
||||
|
|
|
@ -10,4 +10,5 @@ data class BlockEvent(val accountId: String) : Dispatchable
|
|||
data class MuteEvent(val accountId: String) : Dispatchable
|
||||
data class StatusDeletedEvent(val statusId: String) : Dispatchable
|
||||
data class StatusComposedEvent(val status: Status) : Dispatchable
|
||||
data class ProfileEditedEvent(val newProfileData: Account) : Dispatchable
|
||||
data class ProfileEditedEvent(val newProfileData: Account) : Dispatchable
|
||||
data class PreferenceChangedEvent(val preferenceKey: String) : Dispatchable
|
|
@ -21,6 +21,7 @@ import android.arch.persistence.room.PrimaryKey
|
|||
import android.arch.persistence.room.TypeConverters
|
||||
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
|
||||
@Entity(indices = [Index(value = ["domain", "accountId"],
|
||||
unique = true)])
|
||||
|
@ -41,6 +42,10 @@ data class AccountEntity(@field:PrimaryKey(autoGenerate = true) var id: Long,
|
|||
var notificationSound: Boolean = true,
|
||||
var notificationVibration: Boolean = true,
|
||||
var notificationLight: Boolean = true,
|
||||
var defaultPostPrivacy: Status.Visibility = Status.Visibility.PUBLIC,
|
||||
var defaultMediaSensitivity: Boolean = false,
|
||||
var alwaysShowSensitiveMedia: Boolean = false,
|
||||
var mediaPreviewEnabled: Boolean = true,
|
||||
var lastNotificationId: String = "0",
|
||||
var activeNotifications: String = "[]",
|
||||
var emojis: List<Emoji> = emptyList()) {
|
||||
|
|
|
@ -17,6 +17,7 @@ package com.keylesspalace.tusky.db
|
|||
|
||||
import android.util.Log
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
|
||||
/**
|
||||
* This class caches the account database and handles all account related operations
|
||||
|
@ -111,6 +112,8 @@ class AccountManager(db: AppDatabase) {
|
|||
it.username = account.username
|
||||
it.displayName = account.name
|
||||
it.profilePictureUrl = account.avatar
|
||||
it.defaultPostPrivacy = account.source?.privacy ?: Status.Visibility.PUBLIC
|
||||
it.defaultMediaSensitivity = account.source?.sensitive ?: false
|
||||
it.emojis = account.emojis ?: emptyList()
|
||||
|
||||
Log.d(TAG, "updateActiveAccount: saving account with id " + it.id)
|
||||
|
|
|
@ -25,7 +25,7 @@ import android.support.annotation.NonNull;
|
|||
* DB version & declare DAO
|
||||
*/
|
||||
|
||||
@Database(entities = {TootEntity.class, AccountEntity.class, InstanceEntity.class}, version = 9, exportSchema = false)
|
||||
@Database(entities = {TootEntity.class, AccountEntity.class, InstanceEntity.class}, version = 10, exportSchema = false)
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
|
||||
public abstract TootDao tootDao();
|
||||
|
@ -105,4 +105,15 @@ public abstract class AppDatabase extends RoomDatabase {
|
|||
database.execSQL("ALTER TABLE `TootEntity` ADD COLUMN `descriptions` TEXT DEFAULT '[]'");
|
||||
}
|
||||
};
|
||||
|
||||
public static final Migration MIGRATION_9_10 = new Migration(9, 10) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase database) {
|
||||
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `defaultPostPrivacy` INTEGER NOT NULL DEFAULT 1");
|
||||
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `defaultMediaSensitivity` INTEGER NOT NULL DEFAULT 0");
|
||||
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `alwaysShowSensitiveMedia` INTEGER NOT NULL DEFAULT 0");
|
||||
database.execSQL("ALTER TABLE `AccountEntity` ADD COLUMN `mediaPreviewEnabled` INTEGER NOT NULL DEFAULT '1'");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@ import android.arch.persistence.room.TypeConverter
|
|||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
|
||||
class Converters {
|
||||
|
||||
|
@ -33,4 +34,14 @@ class Converters {
|
|||
fun emojiListToJson(emojiList: List<Emoji>?): String {
|
||||
return gson.toJson(emojiList)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun visibilityToInt(visibility: Status.Visibility): Int {
|
||||
return visibility.num
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun intToVisibility(visibility: Int): Status.Visibility {
|
||||
return Status.Visibility.byNum(visibility)
|
||||
}
|
||||
}
|
|
@ -77,8 +77,8 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector
|
||||
abstract fun contributesSavedTootActivity(): SavedTootActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesSPreferencesActivity(): PreferencesActivity
|
||||
@ContributesAndroidInjector(modules = [FragmentBuildersModule::class])
|
||||
abstract fun contributesPreferencesActivity(): PreferencesActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesViewMediaActivity(): ViewMediaActivity
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package com.keylesspalace.tusky.di
|
||||
|
||||
import com.keylesspalace.tusky.fragment.*
|
||||
import com.keylesspalace.tusky.fragment.preference.*
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
|
||||
|
@ -43,4 +44,11 @@ abstract class FragmentBuildersModule {
|
|||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun searchFragment(): SearchFragment
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun notificationPreferencesFragment(): NotificationPreferencesFragment
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun accountPreferencesFragment(): AccountPreferencesFragment
|
||||
|
||||
}
|
|
@ -47,6 +47,7 @@ import com.keylesspalace.tusky.adapter.NotificationsAdapter;
|
|||
import com.keylesspalace.tusky.appstore.BlockEvent;
|
||||
import com.keylesspalace.tusky.appstore.EventHub;
|
||||
import com.keylesspalace.tusky.appstore.FavoriteEvent;
|
||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent;
|
||||
import com.keylesspalace.tusky.appstore.ReblogEvent;
|
||||
import com.keylesspalace.tusky.db.AccountEntity;
|
||||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
|
@ -87,7 +88,6 @@ public class NotificationsFragment extends SFragment implements
|
|||
SwipeRefreshLayout.OnRefreshListener,
|
||||
StatusActionListener,
|
||||
NotificationsAdapter.NotificationActionListener,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||
Injectable {
|
||||
private static final String TAG = "NotificationF"; // logging tag
|
||||
|
||||
|
@ -194,10 +194,9 @@ public class NotificationsFragment extends SFragment implements
|
|||
recyclerView.addItemDecoration(divider);
|
||||
|
||||
adapter = new NotificationsAdapter(this, this);
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(
|
||||
getActivity());
|
||||
alwaysShowSensitiveMedia = preferences.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
boolean mediaPreviewEnabled = preferences.getBoolean("mediaPreviewEnabled", true);
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
alwaysShowSensitiveMedia = accountManager.getActiveAccount().getAlwaysShowSensitiveMedia();
|
||||
boolean mediaPreviewEnabled = accountManager.getActiveAccount().getMediaPreviewEnabled();
|
||||
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
||||
boolean useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false);
|
||||
adapter.setUseAbsoluteTime(useAbsoluteTime);
|
||||
|
@ -273,7 +272,6 @@ public class NotificationsFragment extends SFragment implements
|
|||
* Use a modified scroll listener that both loads more notificationsEnabled as it goes, and hides
|
||||
* the compose button on down-scroll. */
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
hideFab = preferences.getBoolean("fabHide", false);
|
||||
scrollListener = new EndlessOnScrollListener(layoutManager) {
|
||||
@Override
|
||||
|
@ -314,6 +312,8 @@ public class NotificationsFragment extends SFragment implements
|
|||
handleReblogEvent((ReblogEvent) event);
|
||||
} else if (event instanceof BlockEvent) {
|
||||
removeAllByAccountId(((BlockEvent) event).getAccountId());
|
||||
} else if (event instanceof PreferenceChangedEvent) {
|
||||
onPreferenceChanged(((PreferenceChangedEvent) event).getPreferenceKey());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -564,15 +564,14 @@ public class NotificationsFragment extends SFragment implements
|
|||
Log.w(TAG, "Didn't find a notification for ID: " + notificationId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
public void onPreferenceChanged(String key) {
|
||||
switch (key) {
|
||||
case "fabHide": {
|
||||
hideFab = sharedPreferences.getBoolean("fabHide", false);
|
||||
hideFab = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean("fabHide", false);
|
||||
break;
|
||||
}
|
||||
case "mediaPreviewEnabled": {
|
||||
boolean enabled = sharedPreferences.getBoolean("mediaPreviewEnabled", true);
|
||||
boolean enabled = accountManager.getActiveAccount().getMediaPreviewEnabled();
|
||||
if (enabled != adapter.isMediaPreviewEnabled()) {
|
||||
adapter.setMediaPreviewEnabled(enabled);
|
||||
fullyRefresh();
|
||||
|
|
|
@ -1,303 +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.app.AlertDialog;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.support.annotation.XmlRes;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
|
||||
import com.keylesspalace.tusky.BuildConfig;
|
||||
import com.keylesspalace.tusky.PreferencesActivity;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.TuskyApplication;
|
||||
import com.keylesspalace.tusky.db.AccountEntity;
|
||||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PreferencesFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
SharedPreferences sharedPreferences;
|
||||
static boolean httpProxyChanged = false;
|
||||
static boolean pendingRestart = false;
|
||||
|
||||
public static PreferencesFragment newInstance(@XmlRes int preference) {
|
||||
PreferencesFragment fragment = new PreferencesFragment();
|
||||
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("preference", preference);
|
||||
|
||||
fragment.setArguments(args);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
private AccountManager accountManager;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
accountManager = TuskyApplication.getInstance(getActivity()).getServiceLocator()
|
||||
.get(AccountManager.class);
|
||||
|
||||
|
||||
int preference = getArguments().getInt("preference");
|
||||
|
||||
addPreferencesFromResource(preference);
|
||||
|
||||
Preference regexPref = findPreference("tabFilterRegex");
|
||||
if (regexPref != null) regexPref.setOnPreferenceClickListener(pref -> {
|
||||
// Reset the error dialog when shown; if the dialog was closed with the cancel button
|
||||
// while an invalid regex was present, this would otherwise cause buggy behaviour.
|
||||
((EditTextPreference) regexPref).getEditText().setError(null);
|
||||
|
||||
// Test the regex as the user inputs text, ensuring immediate feedback and preventing
|
||||
// setting of an invalid regex, which would cause a crash loop.
|
||||
((EditTextPreference) regexPref).getEditText().addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
try {
|
||||
Pattern.compile(s.toString());
|
||||
((EditTextPreference) regexPref).getEditText().setError(null);
|
||||
AlertDialog dialog = (AlertDialog) ((EditTextPreference) pref).getDialog();
|
||||
if (dialog != null) dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(true);
|
||||
} catch (IllegalArgumentException e) {
|
||||
((AlertDialog) ((EditTextPreference) pref).getDialog()).getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
|
||||
((EditTextPreference) regexPref).getEditText().setError(getString(R.string.error_invalid_regex));
|
||||
}
|
||||
}
|
||||
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
Preference notificationPreferences = findPreference("notificationPreferences");
|
||||
|
||||
if (notificationPreferences != null) {
|
||||
|
||||
AccountEntity activeAccount = accountManager.getActiveAccount();
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O && activeAccount != null) {
|
||||
notificationPreferences.setSummary(getString(R.string.pref_summary_notifications, activeAccount.getFullName()));
|
||||
}
|
||||
|
||||
|
||||
//on Android O and newer, launch the system notification settings instead of the app settings
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
|
||||
notificationPreferences.setOnPreferenceClickListener(pref -> {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
|
||||
|
||||
intent.putExtra("android.provider.extra.APP_PACKAGE", BuildConfig.APPLICATION_ID);
|
||||
|
||||
startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
|
||||
} else {
|
||||
notificationPreferences.setOnPreferenceClickListener(pref -> {
|
||||
PreferencesActivity activity = (PreferencesActivity) getActivity();
|
||||
if (activity != null) {
|
||||
activity.showFragment(R.xml.notification_preferences, R.string.pref_title_edit_notification_settings);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Preference timelineFilterPreferences = findPreference("timelineFilterPreferences");
|
||||
if (timelineFilterPreferences != null) {
|
||||
timelineFilterPreferences.setOnPreferenceClickListener(pref -> {
|
||||
PreferencesActivity activity = (PreferencesActivity) getActivity();
|
||||
if (activity != null) {
|
||||
activity.showFragment(R.xml.timeline_filter_preferences, R.string.pref_title_status_tabs);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
Preference httpProxyPreferences = findPreference("httpProxyPreferences");
|
||||
if (httpProxyPreferences != null) {
|
||||
httpProxyPreferences.setOnPreferenceClickListener(pref -> {
|
||||
PreferencesActivity activity = (PreferencesActivity) getActivity();
|
||||
if (activity != null) {
|
||||
pendingRestart = false;
|
||||
activity.showFragment(R.xml.http_proxy_preferences, R.string.pref_title_http_proxy_settings);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
if (preference == R.xml.notification_preferences) {
|
||||
|
||||
AccountEntity activeAccount = accountManager.getActiveAccount();
|
||||
|
||||
if (activeAccount != null) {
|
||||
|
||||
CheckBoxPreference notificationPref = (CheckBoxPreference) findPreference("notificationsEnabled");
|
||||
notificationPref.setChecked(activeAccount.getNotificationsEnabled());
|
||||
|
||||
CheckBoxPreference mentionedPref = (CheckBoxPreference) findPreference("notificationFilterMentions");
|
||||
mentionedPref.setChecked(activeAccount.getNotificationsMentioned());
|
||||
|
||||
CheckBoxPreference followedPref = (CheckBoxPreference) findPreference("notificationFilterFollows");
|
||||
followedPref.setChecked(activeAccount.getNotificationsFollowed());
|
||||
|
||||
CheckBoxPreference boostedPref = (CheckBoxPreference) findPreference("notificationFilterReblogs");
|
||||
boostedPref.setChecked(activeAccount.getNotificationsReblogged());
|
||||
|
||||
CheckBoxPreference favoritedPref = (CheckBoxPreference) findPreference("notificationFilterFavourites");
|
||||
favoritedPref.setChecked(activeAccount.getNotificationsFavorited());
|
||||
|
||||
CheckBoxPreference soundPref = (CheckBoxPreference) findPreference("notificationAlertSound");
|
||||
soundPref.setChecked(activeAccount.getNotificationSound());
|
||||
|
||||
CheckBoxPreference vibrationPref = (CheckBoxPreference) findPreference("notificationAlertVibrate");
|
||||
vibrationPref.setChecked(activeAccount.getNotificationVibration());
|
||||
|
||||
CheckBoxPreference lightPref = (CheckBoxPreference) findPreference("notificationAlertLight");
|
||||
lightPref.setChecked(activeAccount.getNotificationLight());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
sharedPreferences = getPreferenceManager().getSharedPreferences();
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
updateSummary("httpProxyServer");
|
||||
updateSummary("httpProxyPort");
|
||||
updateHttpProxySummary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||
super.onPause();
|
||||
if (pendingRestart) {
|
||||
pendingRestart = false;
|
||||
httpProxyChanged = false;
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||
String key) {
|
||||
|
||||
switch (key) {
|
||||
case "httpProxyServer":
|
||||
case "httpProxyPort":
|
||||
updateSummary(key);
|
||||
case "httpProxyEnabled":
|
||||
httpProxyChanged = true;
|
||||
return;
|
||||
default:
|
||||
}
|
||||
|
||||
AccountEntity activeAccount = accountManager.getActiveAccount();
|
||||
|
||||
if (activeAccount != null) {
|
||||
switch (key) {
|
||||
case "notificationsEnabled":
|
||||
activeAccount.setNotificationsEnabled(sharedPreferences.getBoolean(key, true));
|
||||
break;
|
||||
case "notificationFilterMentions":
|
||||
activeAccount.setNotificationsMentioned(sharedPreferences.getBoolean(key, true));
|
||||
break;
|
||||
case "notificationFilterFollows":
|
||||
activeAccount.setNotificationsFollowed(sharedPreferences.getBoolean(key, true));
|
||||
break;
|
||||
case "notificationFilterReblogs":
|
||||
activeAccount.setNotificationsReblogged(sharedPreferences.getBoolean(key, true));
|
||||
break;
|
||||
case "notificationFilterFavourites":
|
||||
activeAccount.setNotificationsFavorited(sharedPreferences.getBoolean(key, true));
|
||||
break;
|
||||
case "notificationAlertSound":
|
||||
activeAccount.setNotificationSound(sharedPreferences.getBoolean(key, true));
|
||||
break;
|
||||
case "notificationAlertVibrate":
|
||||
activeAccount.setNotificationVibration(sharedPreferences.getBoolean(key, true));
|
||||
break;
|
||||
case "notificationAlertLight":
|
||||
activeAccount.setNotificationLight(sharedPreferences.getBoolean(key, true));
|
||||
break;
|
||||
}
|
||||
accountManager.saveAccount(activeAccount);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void updateSummary(String key) {
|
||||
switch (key) {
|
||||
case "httpProxyServer":
|
||||
case "httpProxyPort":
|
||||
EditTextPreference editTextPreference = (EditTextPreference) findPreference(key);
|
||||
if (editTextPreference != null) {
|
||||
editTextPreference.setSummary(editTextPreference.getText());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHttpProxySummary() {
|
||||
Preference httpProxyPref = findPreference("httpProxyPreferences");
|
||||
if (httpProxyPref != null) {
|
||||
if (httpProxyChanged) {
|
||||
pendingRestart = true;
|
||||
}
|
||||
|
||||
Boolean httpProxyEnabled = sharedPreferences.getBoolean("httpProxyEnabled", false);
|
||||
|
||||
String httpServer = sharedPreferences.getString("httpProxyServer", "");
|
||||
|
||||
try {
|
||||
int httpPort = Integer.parseInt(sharedPreferences.getString("httpProxyPort", "-1"));
|
||||
|
||||
if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0 && httpPort < 65535)) {
|
||||
httpProxyPref.setSummary(httpServer + ":" + httpPort);
|
||||
return;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// user has entered wrong port, fall back to empty summary
|
||||
}
|
||||
|
||||
httpProxyPref.setSummary("");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,10 +50,12 @@ import com.keylesspalace.tusky.appstore.BlockEvent;
|
|||
import com.keylesspalace.tusky.appstore.EventHub;
|
||||
import com.keylesspalace.tusky.appstore.FavoriteEvent;
|
||||
import com.keylesspalace.tusky.appstore.MuteEvent;
|
||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent;
|
||||
import com.keylesspalace.tusky.appstore.ReblogEvent;
|
||||
import com.keylesspalace.tusky.appstore.StatusComposedEvent;
|
||||
import com.keylesspalace.tusky.appstore.StatusDeletedEvent;
|
||||
import com.keylesspalace.tusky.appstore.UnfollowEvent;
|
||||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
import com.keylesspalace.tusky.di.Injectable;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
|
||||
|
@ -90,7 +92,6 @@ import static com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvid
|
|||
public class TimelineFragment extends SFragment implements
|
||||
SwipeRefreshLayout.OnRefreshListener,
|
||||
StatusActionListener,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||
Injectable {
|
||||
private static final String TAG = "TimelineF"; // logging tag
|
||||
private static final String KIND_ARG = "kind";
|
||||
|
@ -119,6 +120,9 @@ public class TimelineFragment extends SFragment implements
|
|||
public TimelineCases timelineCases;
|
||||
@Inject
|
||||
public EventHub eventHub;
|
||||
@Inject
|
||||
public AccountManager accountManager;
|
||||
|
||||
private boolean eventRegistered = false;
|
||||
|
||||
private SwipeRefreshLayout swipeRefreshLayout;
|
||||
|
@ -244,9 +248,8 @@ public class TimelineFragment extends SFragment implements
|
|||
|
||||
private void setupTimelinePreferences() {
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
alwaysShowSensitiveMedia = preferences.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
boolean mediaPreviewEnabled = preferences.getBoolean("mediaPreviewEnabled", true);
|
||||
alwaysShowSensitiveMedia = accountManager.getActiveAccount().getAlwaysShowSensitiveMedia();
|
||||
boolean mediaPreviewEnabled = accountManager.getActiveAccount().getMediaPreviewEnabled();
|
||||
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
||||
boolean useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false);
|
||||
adapter.setUseAbsoluteTime(useAbsoluteTime);
|
||||
|
@ -413,6 +416,8 @@ public class TimelineFragment extends SFragment implements
|
|||
} else if (event instanceof StatusComposedEvent) {
|
||||
Status status = ((StatusComposedEvent) event).getStatus();
|
||||
handleStatusComposeEvent(status);
|
||||
} else if (event instanceof PreferenceChangedEvent) {
|
||||
onPreferenceChanged(((PreferenceChangedEvent) event).getPreferenceKey());
|
||||
}
|
||||
});
|
||||
eventRegistered = true;
|
||||
|
@ -630,15 +635,15 @@ public class TimelineFragment extends SFragment implements
|
|||
super.viewAccount(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
private void onPreferenceChanged(String key) {
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
switch (key) {
|
||||
case "fabHide": {
|
||||
hideFab = sharedPreferences.getBoolean("fabHide", false);
|
||||
break;
|
||||
}
|
||||
case "mediaPreviewEnabled": {
|
||||
boolean enabled = sharedPreferences.getBoolean("mediaPreviewEnabled", true);
|
||||
boolean enabled = accountManager.getActiveAccount().getMediaPreviewEnabled();
|
||||
boolean oldMediaPreviewEnabled = adapter.getMediaPreviewEnabled();
|
||||
if (enabled != oldMediaPreviewEnabled) {
|
||||
adapter.setMediaPreviewEnabled(enabled);
|
||||
|
@ -682,7 +687,7 @@ public class TimelineFragment extends SFragment implements
|
|||
}
|
||||
case "alwaysShowSensitiveMedia": {
|
||||
//it is ok if only newly loaded statuses are affected, no need to fully refresh
|
||||
alwaysShowSensitiveMedia = sharedPreferences.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
alwaysShowSensitiveMedia = accountManager.getActiveAccount().getAlwaysShowSensitiveMedia();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,8 +157,8 @@ public final class ViewThreadFragment extends SFragment implements
|
|||
threadLineDrawable));
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(
|
||||
getActivity());
|
||||
alwaysShowSensitiveMedia = preferences.getBoolean("alwaysShowSensitiveMedia", false);
|
||||
boolean mediaPreviewEnabled = preferences.getBoolean("mediaPreviewEnabled", true);
|
||||
alwaysShowSensitiveMedia = accountManager.getActiveAccount().getAlwaysShowSensitiveMedia();
|
||||
boolean mediaPreviewEnabled = accountManager.getActiveAccount().getMediaPreviewEnabled();
|
||||
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
||||
boolean useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false);
|
||||
adapter.setUseAbsoluteTime(useAbsoluteTime);
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
/* Copyright 2018 Conny Duck
|
||||
*
|
||||
* 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.preference
|
||||
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.v14.preference.SwitchPreference
|
||||
import android.support.v7.preference.ListPreference
|
||||
import android.support.v7.preference.Preference
|
||||
import android.support.v7.preference.PreferenceFragmentCompat
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import com.keylesspalace.tusky.AccountListActivity
|
||||
import com.keylesspalace.tusky.BuildConfig
|
||||
import com.keylesspalace.tusky.PreferencesActivity
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.ThemeUtils
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class AccountPreferencesFragment : PreferenceFragmentCompat(),
|
||||
Preference.OnPreferenceChangeListener, Preference.OnPreferenceClickListener,
|
||||
Injectable {
|
||||
|
||||
@Inject
|
||||
lateinit var accountManager: AccountManager
|
||||
|
||||
@Inject
|
||||
lateinit var mastodonApi: MastodonApi
|
||||
|
||||
@Inject
|
||||
lateinit var eventHub: EventHub
|
||||
|
||||
private lateinit var notificationPreference: Preference
|
||||
private lateinit var mutedUsersPreference: Preference
|
||||
private lateinit var blockedUsersPreference: Preference
|
||||
|
||||
private lateinit var defaultPostPrivacyPreference: ListPreference
|
||||
private lateinit var defaultMediaSensitivityPreference: SwitchPreference
|
||||
private lateinit var alwaysShowSensitiveMediaPreference: SwitchPreference
|
||||
private lateinit var mediaPreviewEnabledPreference: SwitchPreference
|
||||
|
||||
private val iconSize by lazy {resources.getDimensionPixelSize(R.dimen.preference_icon_size)}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.account_preferences)
|
||||
|
||||
notificationPreference = findPreference("notificationPreference")
|
||||
mutedUsersPreference = findPreference("mutedUsersPreference")
|
||||
blockedUsersPreference = findPreference("blockedUsersPreference")
|
||||
defaultPostPrivacyPreference = findPreference("defaultPostPrivacy") as ListPreference
|
||||
defaultMediaSensitivityPreference = findPreference("defaultMediaSensitivity") as SwitchPreference
|
||||
mediaPreviewEnabledPreference = findPreference("mediaPreviewEnabled") as SwitchPreference
|
||||
alwaysShowSensitiveMediaPreference = findPreference("alwaysShowSensitiveMedia") as SwitchPreference
|
||||
|
||||
notificationPreference.icon = IconicsDrawable(context, GoogleMaterial.Icon.gmd_notifications).sizePx(iconSize).color(ThemeUtils.getColor(context, R.attr.toolbar_icon_tint))
|
||||
mutedUsersPreference.icon = getTintedIcon(R.drawable.ic_mute_24dp)
|
||||
blockedUsersPreference.icon = IconicsDrawable(context, GoogleMaterial.Icon.gmd_block).sizePx(iconSize).color(ThemeUtils.getColor(context, R.attr.toolbar_icon_tint))
|
||||
|
||||
notificationPreference.onPreferenceClickListener = this
|
||||
mutedUsersPreference.onPreferenceClickListener = this
|
||||
blockedUsersPreference.onPreferenceClickListener = this
|
||||
|
||||
defaultPostPrivacyPreference.onPreferenceChangeListener = this
|
||||
defaultMediaSensitivityPreference.onPreferenceChangeListener = this
|
||||
mediaPreviewEnabledPreference.onPreferenceChangeListener = this
|
||||
alwaysShowSensitiveMediaPreference.onPreferenceChangeListener = this
|
||||
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
accountManager.activeAccount?.let {
|
||||
|
||||
defaultPostPrivacyPreference.value = it.defaultPostPrivacy.serverString()
|
||||
defaultPostPrivacyPreference.icon = getIconForVisibility(it.defaultPostPrivacy)
|
||||
|
||||
defaultMediaSensitivityPreference.isChecked = it.defaultMediaSensitivity
|
||||
defaultMediaSensitivityPreference.icon = getIconForSensitivity(it.defaultMediaSensitivity)
|
||||
|
||||
mediaPreviewEnabledPreference.isChecked = it.mediaPreviewEnabled
|
||||
alwaysShowSensitiveMediaPreference.isChecked = it.alwaysShowSensitiveMedia
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
|
||||
when(preference) {
|
||||
defaultPostPrivacyPreference -> {
|
||||
preference.icon = getIconForVisibility(Status.Visibility.byString(newValue as String))
|
||||
syncWithServer(visibility = newValue)
|
||||
}
|
||||
defaultMediaSensitivityPreference -> {
|
||||
preference.icon = getIconForSensitivity(newValue as Boolean)
|
||||
syncWithServer(sensitive = newValue)
|
||||
}
|
||||
mediaPreviewEnabledPreference -> {
|
||||
accountManager.activeAccount?.let {
|
||||
it.mediaPreviewEnabled = newValue as Boolean
|
||||
accountManager.saveAccount(it)
|
||||
}
|
||||
}
|
||||
alwaysShowSensitiveMediaPreference -> {
|
||||
accountManager.activeAccount?.let {
|
||||
it.alwaysShowSensitiveMedia = newValue as Boolean
|
||||
accountManager.saveAccount(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eventHub.dispatch(PreferenceChangedEvent(preference.key))
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPreferenceClick(preference: Preference): Boolean {
|
||||
|
||||
when(preference) {
|
||||
notificationPreference -> {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val intent = Intent()
|
||||
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
|
||||
intent.putExtra("android.provider.extra.APP_PACKAGE", BuildConfig.APPLICATION_ID)
|
||||
startActivity(intent)
|
||||
} else {
|
||||
activity?.let {
|
||||
val intent = PreferencesActivity.newIntent(it, PreferencesActivity.NOTIFICATION_PREFERENCES)
|
||||
it.startActivity(intent)
|
||||
it.overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
|
||||
}
|
||||
|
||||
}
|
||||
return true
|
||||
}
|
||||
mutedUsersPreference -> {
|
||||
val intent = Intent(context, AccountListActivity::class.java)
|
||||
intent.putExtra("type", AccountListActivity.Type.MUTES)
|
||||
activity?.startActivity(intent)
|
||||
activity?.overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
|
||||
return true
|
||||
}
|
||||
blockedUsersPreference -> {
|
||||
val intent = Intent(context, AccountListActivity::class.java)
|
||||
intent.putExtra("type", AccountListActivity.Type.BLOCKS)
|
||||
activity?.startActivity(intent)
|
||||
activity?.overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
|
||||
return true
|
||||
}
|
||||
|
||||
else -> return false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun syncWithServer(visibility: String? = null, sensitive: Boolean? = null) {
|
||||
mastodonApi.accountUpdateSource(visibility, sensitive)
|
||||
.enqueue(object: Callback<Account>{
|
||||
override fun onResponse(call: Call<Account>, response: Response<Account>) {
|
||||
val account = response.body()
|
||||
if(response.isSuccessful && account != null) {
|
||||
|
||||
accountManager.activeAccount?.let {
|
||||
it.defaultPostPrivacy = account.source?.privacy ?: Status.Visibility.PUBLIC
|
||||
it.defaultMediaSensitivity = account.source?.sensitive ?: false
|
||||
accountManager.saveAccount(it)
|
||||
}
|
||||
} else {
|
||||
Log.e("AccountPreferences", "failed updating settings on server")
|
||||
showErrorSnackbar(visibility, sensitive)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<Account>, t: Throwable) {
|
||||
Log.e("AccountPreferences", "failed updating settings on server", t)
|
||||
showErrorSnackbar(visibility, sensitive)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
private fun showErrorSnackbar(visibility: String?, sensitive: Boolean?) {
|
||||
view?.let {view ->
|
||||
Snackbar.make(view, R.string.pref_failed_to_sync, Snackbar.LENGTH_LONG)
|
||||
.setAction(R.string.action_retry) { syncWithServer( visibility, sensitive)}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getIconForVisibility(visibility: Status.Visibility): Drawable? {
|
||||
val drawableId = when (visibility) {
|
||||
Status.Visibility.PRIVATE -> R.drawable.ic_lock_outline_24dp
|
||||
|
||||
Status.Visibility.UNLISTED -> R.drawable.ic_lock_open_24dp
|
||||
|
||||
else -> R.drawable.ic_public_24dp
|
||||
}
|
||||
|
||||
return getTintedIcon(drawableId)
|
||||
}
|
||||
|
||||
private fun getIconForSensitivity(sensitive: Boolean): Drawable? {
|
||||
val drawableId = if (sensitive) {
|
||||
R.drawable.ic_hide_media_24dp
|
||||
} else {
|
||||
R.drawable.ic_eye_24dp
|
||||
}
|
||||
|
||||
return getTintedIcon(drawableId)
|
||||
}
|
||||
|
||||
private fun getTintedIcon(iconId: Int): Drawable? {
|
||||
val drawable = context?.getDrawable(iconId)
|
||||
ThemeUtils.setDrawableTint(context, drawable, R.attr.toolbar_icon_tint)
|
||||
return drawable
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(): AccountPreferencesFragment {
|
||||
return AccountPreferencesFragment()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/* Copyright 2018 Conny Duck
|
||||
*
|
||||
* 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.preference
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v14.preference.SwitchPreference
|
||||
import android.support.v7.preference.Preference
|
||||
import android.support.v7.preference.PreferenceFragmentCompat
|
||||
import android.view.View
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.util.NotificationHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
class NotificationPreferencesFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener, Injectable {
|
||||
|
||||
@Inject
|
||||
lateinit var accountManager: AccountManager
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.notification_preferences)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val activeAccount = accountManager.activeAccount
|
||||
|
||||
if (activeAccount != null) {
|
||||
|
||||
val notificationPref = findPreference("notificationsEnabled") as SwitchPreference
|
||||
notificationPref.isChecked = activeAccount.notificationsEnabled
|
||||
notificationPref.onPreferenceChangeListener = this
|
||||
|
||||
val mentionedPref = findPreference("notificationFilterMentions") as SwitchPreference
|
||||
mentionedPref.isChecked = activeAccount.notificationsMentioned
|
||||
mentionedPref.onPreferenceChangeListener = this
|
||||
|
||||
val followedPref = findPreference("notificationFilterFollows") as SwitchPreference
|
||||
followedPref.isChecked = activeAccount.notificationsFollowed
|
||||
followedPref.onPreferenceChangeListener = this
|
||||
|
||||
val boostedPref = findPreference("notificationFilterReblogs") as SwitchPreference
|
||||
boostedPref.isChecked = activeAccount.notificationsReblogged
|
||||
boostedPref.onPreferenceChangeListener = this
|
||||
|
||||
val favoritedPref = findPreference("notificationFilterFavourites") as SwitchPreference
|
||||
favoritedPref.isChecked = activeAccount.notificationsFavorited
|
||||
favoritedPref.onPreferenceChangeListener = this
|
||||
|
||||
val soundPref = findPreference("notificationAlertSound") as SwitchPreference
|
||||
soundPref.isChecked = activeAccount.notificationSound
|
||||
soundPref.onPreferenceChangeListener = this
|
||||
|
||||
val vibrationPref = findPreference("notificationAlertVibrate") as SwitchPreference
|
||||
vibrationPref.isChecked = activeAccount.notificationVibration
|
||||
vibrationPref.onPreferenceChangeListener = this
|
||||
|
||||
val lightPref = findPreference("notificationAlertLight") as SwitchPreference
|
||||
lightPref.isChecked = activeAccount.notificationLight
|
||||
lightPref.onPreferenceChangeListener = this
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean {
|
||||
|
||||
val activeAccount = accountManager.activeAccount
|
||||
|
||||
if (activeAccount != null) {
|
||||
when (preference.key) {
|
||||
"notificationsEnabled" -> {
|
||||
activeAccount.notificationsEnabled = newValue as Boolean
|
||||
if(NotificationHelper.areNotificationsEnabled(preference.context, accountManager)) {
|
||||
NotificationHelper.enablePullNotifications()
|
||||
} else {
|
||||
NotificationHelper.disablePullNotifications()
|
||||
}
|
||||
}
|
||||
"notificationFilterMentions" -> activeAccount.notificationsMentioned = newValue as Boolean
|
||||
"notificationFilterFollows" -> activeAccount.notificationsFollowed = newValue as Boolean
|
||||
"notificationFilterReblogs" -> activeAccount.notificationsReblogged = newValue as Boolean
|
||||
"notificationFilterFavourites" -> activeAccount.notificationsFavorited = newValue as Boolean
|
||||
"notificationAlertSound" -> activeAccount.notificationSound = newValue as Boolean
|
||||
"notificationAlertVibrate" -> activeAccount.notificationVibration = newValue as Boolean
|
||||
"notificationAlertLight" -> activeAccount.notificationLight = newValue as Boolean
|
||||
}
|
||||
accountManager.saveAccount(activeAccount)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(): NotificationPreferencesFragment {
|
||||
return NotificationPreferencesFragment()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/* Copyright 2018 Conny Duck
|
||||
*
|
||||
* 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.preference
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v7.preference.PreferenceFragmentCompat
|
||||
import com.keylesspalace.tusky.PreferencesActivity
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.util.ThemeUtils
|
||||
import com.keylesspalace.tusky.util.getNonNullString
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
|
||||
class PreferencesFragment : PreferenceFragmentCompat() {
|
||||
|
||||
private val iconSize by lazy {resources.getDimensionPixelSize(R.dimen.preference_icon_size)}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
||||
addPreferencesFromResource(R.xml.preferences)
|
||||
|
||||
val themePreference = findPreference("appTheme")
|
||||
themePreference.icon = IconicsDrawable(context, GoogleMaterial.Icon.gmd_palette).sizePx(iconSize).color(ThemeUtils.getColor(context, R.attr.toolbar_icon_tint))
|
||||
|
||||
val emojiPreference = findPreference("emojiCompat")
|
||||
emojiPreference.icon = IconicsDrawable(context, GoogleMaterial.Icon.gmd_sentiment_satisfied).sizePx(iconSize).color(ThemeUtils.getColor(context, R.attr.toolbar_icon_tint))
|
||||
|
||||
val textSizePreference = findPreference("statusTextSize")
|
||||
textSizePreference.icon = IconicsDrawable(context, GoogleMaterial.Icon.gmd_format_size).sizePx(iconSize).color(ThemeUtils.getColor(context, R.attr.toolbar_icon_tint))
|
||||
|
||||
val timelineFilterPreferences = findPreference("timelineFilterPreferences")
|
||||
timelineFilterPreferences.setOnPreferenceClickListener { _ ->
|
||||
activity?.let {
|
||||
val intent = PreferencesActivity.newIntent(it, PreferencesActivity.TAB_FILTER_PREFERENCES)
|
||||
it.startActivity(intent)
|
||||
it.overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
val httpProxyPreferences = findPreference("httpProxyPreferences")
|
||||
httpProxyPreferences.setOnPreferenceClickListener { _ ->
|
||||
activity?.let {
|
||||
val intent = PreferencesActivity.newIntent(it, PreferencesActivity.PROXY_PREFERENCES)
|
||||
it.startActivity(intent)
|
||||
it.overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updateHttpProxySummary()
|
||||
}
|
||||
|
||||
private fun updateHttpProxySummary() {
|
||||
|
||||
val httpProxyPref = findPreference("httpProxyPreferences")
|
||||
|
||||
val sharedPreferences = preferenceManager.sharedPreferences
|
||||
|
||||
val httpProxyEnabled = sharedPreferences.getBoolean("httpProxyEnabled", false)
|
||||
|
||||
val httpServer = sharedPreferences.getNonNullString("httpProxyServer", "")
|
||||
|
||||
try {
|
||||
val httpPort = sharedPreferences.getNonNullString("httpProxyPort", "-1").toInt()
|
||||
|
||||
if (httpProxyEnabled && httpServer.isNotBlank() && httpPort > 0 && httpPort < 65535) {
|
||||
httpProxyPref.summary = "$httpServer:$httpPort"
|
||||
return
|
||||
}
|
||||
} catch (e: NumberFormatException) {
|
||||
// user has entered wrong port, fall back to empty summary
|
||||
}
|
||||
|
||||
httpProxyPref.summary = ""
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(): PreferencesFragment {
|
||||
return PreferencesFragment()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/* Copyright 2018 Conny Duck
|
||||
|
||||
* 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.preference
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.support.v7.preference.EditTextPreference
|
||||
import android.support.v7.preference.PreferenceFragmentCompat
|
||||
import com.keylesspalace.tusky.R
|
||||
|
||||
class ProxyPreferencesFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private var pendingRestart = false
|
||||
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.http_proxy_preferences)
|
||||
|
||||
sharedPreferences = preferenceManager.sharedPreferences
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||
|
||||
updateSummary("httpProxyServer")
|
||||
updateSummary("httpProxyPort")
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||
|
||||
if (pendingRestart) {
|
||||
pendingRestart = false
|
||||
System.exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
updateSummary (key)
|
||||
}
|
||||
|
||||
private fun updateSummary(key: String) {
|
||||
when (key) {
|
||||
"httpProxyServer", "httpProxyPort" -> {
|
||||
val editTextPreference = findPreference(key) as EditTextPreference
|
||||
editTextPreference.summary = editTextPreference.text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): ProxyPreferencesFragment {
|
||||
return ProxyPreferencesFragment()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/* Copyright 2018 Conny Duck
|
||||
*
|
||||
* 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.preference
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.preference.PreferenceFragmentCompat
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.widget.EditText
|
||||
import com.keylesspalace.tusky.R
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class TabFilterPreferencesFragment : PreferenceFragmentCompat() {
|
||||
|
||||
private lateinit var sharedPreferences: SharedPreferences
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.timeline_filter_preferences)
|
||||
|
||||
sharedPreferences = preferenceManager.sharedPreferences
|
||||
|
||||
val regexPref = findPreference("tabFilterRegex")
|
||||
if (regexPref != null) {
|
||||
|
||||
regexPref.summary = sharedPreferences.getString("tabFilterRegex", "")
|
||||
regexPref.setOnPreferenceClickListener {
|
||||
|
||||
val editText = EditText(requireContext())
|
||||
editText.setText(sharedPreferences.getString("tabFilterRegex", ""))
|
||||
|
||||
val dialog = AlertDialog.Builder(requireContext())
|
||||
.setTitle(R.string.pref_title_filter_regex)
|
||||
.setView(editText)
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
sharedPreferences
|
||||
.edit()
|
||||
.putString("tabFilterRegex", editText.text.toString())
|
||||
.apply()
|
||||
regexPref.summary = editText.text.toString()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
|
||||
editText.addTextChangedListener(object : TextWatcher {
|
||||
override fun afterTextChanged(newRegex: Editable) {
|
||||
try {
|
||||
Pattern.compile(newRegex.toString())
|
||||
editText.error = null
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = true
|
||||
} catch (e: IllegalArgumentException) {
|
||||
editText.error = getString(R.string.error_invalid_regex)
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s1: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
|
||||
override fun onTextChanged(s1: CharSequence, start: Int, before: Int, count: Int) {}
|
||||
})
|
||||
dialog.show()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(): TabFilterPreferencesFragment {
|
||||
return TabFilterPreferencesFragment()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -166,6 +166,11 @@ public interface MastodonApi {
|
|||
@GET("api/v1/accounts/verify_credentials")
|
||||
Call<Account> accountVerifyCredentials();
|
||||
|
||||
@FormUrlEncoded
|
||||
@PATCH("api/v1/accounts/update_credentials")
|
||||
Call<Account> accountUpdateSource(@Nullable @Field("source[privacy]") String privacy,
|
||||
@Nullable @Field("source[sensitive]") Boolean sensitive);
|
||||
|
||||
@Multipart
|
||||
@PATCH("api/v1/accounts/update_credentials")
|
||||
Call<Account> accountUpdateCredentials(
|
||||
|
|
|
@ -37,6 +37,8 @@ import android.support.v4.content.ContextCompat;
|
|||
import android.support.v4.text.BidiFormatter;
|
||||
import android.util.Log;
|
||||
|
||||
import com.evernote.android.job.JobManager;
|
||||
import com.evernote.android.job.JobRequest;
|
||||
import com.keylesspalace.tusky.BuildConfig;
|
||||
import com.keylesspalace.tusky.MainActivity;
|
||||
import com.keylesspalace.tusky.R;
|
||||
|
@ -103,6 +105,13 @@ public class NotificationHelper {
|
|||
public static final String CHANNEL_BOOST = "CHANNEL_BOOST";
|
||||
public static final String CHANNEL_FAVOURITE = "CHANNEL_FAVOURITE";
|
||||
|
||||
/**
|
||||
* time in minutes between notification checks
|
||||
* note that this cannot be less than 15 minutes due to Android battery saving constraints
|
||||
*/
|
||||
private static final int NOTIFICATION_CHECK_INTERVAL_MINUTES = 15;
|
||||
|
||||
|
||||
/**
|
||||
* Takes a given Mastodon notification and either creates a new Android notification or updates
|
||||
* the state of the existing notification to reflect the new interaction.
|
||||
|
@ -424,6 +433,25 @@ public class NotificationHelper {
|
|||
|
||||
}
|
||||
|
||||
public static void enablePullNotifications() {
|
||||
long checkInterval = 1000 * 60 * NOTIFICATION_CHECK_INTERVAL_MINUTES;
|
||||
|
||||
new JobRequest.Builder(NotificationPullJobCreator.NOTIFICATIONS_JOB_TAG)
|
||||
.setPeriodic(checkInterval)
|
||||
.setUpdateCurrent(true)
|
||||
.setRequiredNetworkType(JobRequest.NetworkType.CONNECTED)
|
||||
.build()
|
||||
.scheduleAsync();
|
||||
|
||||
Log.d(TAG, "enabled notification checks with "+ NOTIFICATION_CHECK_INTERVAL_MINUTES + "min interval");
|
||||
}
|
||||
|
||||
public static void disablePullNotifications() {
|
||||
JobManager.instance().cancelAllForTag(NotificationPullJobCreator.NOTIFICATIONS_JOB_TAG);
|
||||
Log.d(TAG, "disabled notification checks");
|
||||
|
||||
}
|
||||
|
||||
public static void clearNotificationsForActiveAccount(@NonNull Context context, @NonNull AccountManager accountManager) {
|
||||
AccountEntity account = accountManager.getActiveAccount();
|
||||
if (account != null) {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* You should have received a copy of the GNU Lesser General Public License along with Tusky. If
|
||||
* not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
package com.keylesspalace.tusky;
|
||||
package com.keylesspalace.tusky.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
@ -26,7 +26,6 @@ import com.keylesspalace.tusky.db.AccountEntity;
|
|||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.network.MastodonApi;
|
||||
import com.keylesspalace.tusky.util.NotificationHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
|
@ -98,10 +97,10 @@ public final class NotificationPullJobCreator implements JobCreator {
|
|||
if (notifications.isSuccessful()) {
|
||||
onNotificationsReceived(account, notifications.body());
|
||||
} else {
|
||||
Log.w(TAG, "error receiving notificationsEnabled");
|
||||
Log.w(TAG, "error receiving notifications");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "error receiving notificationsEnabled", e);
|
||||
Log.w(TAG, "error receiving notifications", e);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.keylesspalace.tusky.util
|
||||
|
||||
import android.content.SharedPreferences
|
||||
|
||||
fun SharedPreferences.getNonNullString(key: String, defValue: String): String {
|
||||
return this.getString(key, defValue) ?: defValue
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue