Reverts notifications from MQTT prototype to pull notifications.
This commit is contained in:
parent
14d02e72b7
commit
f68f6d7473
9 changed files with 295 additions and 148 deletions
|
@ -98,7 +98,7 @@
|
|||
|
||||
<receiver android:name=".receiver.NotificationClearBroadcastReceiver" />
|
||||
|
||||
<service android:name="org.eclipse.paho.android.service.MqttService" />
|
||||
<service android:name=".service.PullNotificationService" />
|
||||
<service
|
||||
tools:targetApi="24"
|
||||
android:name="com.keylesspalace.tusky.service.TuskyTileService"
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
package com.keylesspalace.tusky;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
@ -22,24 +25,23 @@ import android.graphics.Color;
|
|||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.Spanned;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Menu;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.keylesspalace.tusky.entity.Session;
|
||||
import com.keylesspalace.tusky.json.SpannedTypeAdapter;
|
||||
import com.keylesspalace.tusky.json.StringWithEmoji;
|
||||
import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter;
|
||||
import com.keylesspalace.tusky.network.MastodonApi;
|
||||
import com.keylesspalace.tusky.network.TuskyApi;
|
||||
import com.keylesspalace.tusky.service.PullNotificationService;
|
||||
import com.keylesspalace.tusky.util.OkHttpUtils;
|
||||
import com.keylesspalace.tusky.util.PushNotificationClient;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -48,18 +50,14 @@ import okhttp3.Interceptor;
|
|||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
public class BaseActivity extends AppCompatActivity {
|
||||
private static final String TAG = "BaseActivity"; // logging tag
|
||||
protected static final int SERVICE_REQUEST_CODE = 8574603; // This number is arbitrary.
|
||||
|
||||
public MastodonApi mastodonApi;
|
||||
public TuskyApi tuskyApi;
|
||||
protected PushNotificationClient pushNotificationClient;
|
||||
protected Dispatcher mastodonApiDispatcher;
|
||||
|
||||
@Override
|
||||
|
@ -69,7 +67,6 @@ public class BaseActivity extends AppCompatActivity {
|
|||
redirectIfNotLoggedIn();
|
||||
createMastodonApi();
|
||||
createTuskyApi();
|
||||
createPushNotificationClient();
|
||||
|
||||
/* There isn't presently a way to globally change the theme of a whole application at
|
||||
* runtime, just individual activities. So, each activity has to set its theme before any
|
||||
|
@ -173,11 +170,6 @@ public class BaseActivity extends AppCompatActivity {
|
|||
tuskyApi = retrofit.create(TuskyApi.class);
|
||||
}
|
||||
|
||||
protected void createPushNotificationClient() {
|
||||
pushNotificationClient = new PushNotificationClient(getApplicationContext(),
|
||||
"ssl://" + getString(R.string.tusky_api_url) + ":8883");
|
||||
}
|
||||
|
||||
protected void redirectIfNotLoggedIn() {
|
||||
SharedPreferences preferences = getPrivatePreferences();
|
||||
String domain = preferences.getString("domain", null);
|
||||
|
@ -209,66 +201,47 @@ public class BaseActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
protected void enablePushNotifications() {
|
||||
Callback<ResponseBody> callback = new Callback<ResponseBody>() {
|
||||
@Override
|
||||
public void onResponse(Call<ResponseBody> call,
|
||||
retrofit2.Response<ResponseBody> response) {
|
||||
if (response.isSuccessful()) {
|
||||
pushNotificationClient.subscribeToTopic(getPushNotificationTopic());
|
||||
pushNotificationClient.connect(BaseActivity.this);
|
||||
} else {
|
||||
onEnablePushNotificationsFailure(response.message());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||
onEnablePushNotificationsFailure(t.getMessage());
|
||||
}
|
||||
};
|
||||
String deviceToken = pushNotificationClient.getDeviceToken();
|
||||
Session session = new Session(getDomain(), getAccessToken(), deviceToken);
|
||||
tuskyApi.register(session)
|
||||
.enqueue(callback);
|
||||
}
|
||||
|
||||
private void onEnablePushNotificationsFailure(String message) {
|
||||
Log.e(TAG, "Enabling push notifications failed. " + message);
|
||||
// Start up the PullNotificationService on a repeating interval.
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String minutesString = preferences.getString("pullNotificationCheckInterval", "15");
|
||||
long minutes = Long.valueOf(minutesString);
|
||||
long checkInterval = 1000 * 60 * minutes;
|
||||
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
Intent intent = new Intent(this, PullNotificationService.class);
|
||||
PendingIntent serviceAlarmIntent = PendingIntent.getService(this, SERVICE_REQUEST_CODE,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime(), checkInterval, serviceAlarmIntent);
|
||||
}
|
||||
|
||||
protected void disablePushNotifications() {
|
||||
Callback<ResponseBody> callback = new Callback<ResponseBody>() {
|
||||
@Override
|
||||
public void onResponse(Call<ResponseBody> call,
|
||||
retrofit2.Response<ResponseBody> response) {
|
||||
if (response.isSuccessful()) {
|
||||
pushNotificationClient.unsubscribeToTopic(getPushNotificationTopic());
|
||||
} else {
|
||||
onDisablePushNotificationsFailure();
|
||||
}
|
||||
// Cancel the repeating call for "pull" notifications.
|
||||
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
Intent intent = new Intent(this, PullNotificationService.class);
|
||||
PendingIntent serviceAlarmIntent = PendingIntent.getService(this, SERVICE_REQUEST_CODE,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
alarmManager.cancel(serviceAlarmIntent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<ResponseBody> call, Throwable t) {
|
||||
onDisablePushNotificationsFailure();
|
||||
}
|
||||
};
|
||||
String deviceToken = pushNotificationClient.getDeviceToken();
|
||||
Session session = new Session(getDomain(), getAccessToken(), deviceToken);
|
||||
tuskyApi.unregister(session)
|
||||
.enqueue(callback);
|
||||
protected void clearNotifications() {
|
||||
SharedPreferences notificationPreferences = getApplicationContext()
|
||||
.getSharedPreferences("Notifications", MODE_PRIVATE);
|
||||
notificationPreferences.edit()
|
||||
.putString("current", "[]")
|
||||
.apply();
|
||||
|
||||
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
manager.cancel(PullNotificationService.NOTIFY_ID);
|
||||
}
|
||||
|
||||
private void onDisablePushNotificationsFailure() {
|
||||
Log.e(TAG, "Disabling push notifications failed.");
|
||||
}
|
||||
|
||||
private String getPushNotificationTopic() {
|
||||
return String.format("%s/%s/#", getDomain(), getAccessToken());
|
||||
}
|
||||
|
||||
private String getDomain() {
|
||||
return getPrivatePreferences()
|
||||
.getString("domain", null);
|
||||
protected void setPullNotificationCheckInterval(long minutes) {
|
||||
long checkInterval = 1000 * 60 * minutes;
|
||||
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
|
||||
Intent intent = new Intent(this, PullNotificationService.class);
|
||||
PendingIntent serviceAlarmIntent = PendingIntent.getService(this, SERVICE_REQUEST_CODE,
|
||||
intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
alarmManager.cancel(serviceAlarmIntent);
|
||||
alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime(), checkInterval, serviceAlarmIntent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -210,17 +210,19 @@ public class MainActivity extends BaseActivity {
|
|||
composeButton = floatingBtn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
|
||||
ArrayList<Integer> pageHistoryList = new ArrayList<>();
|
||||
pageHistoryList.addAll(pageHistory);
|
||||
outState.putIntegerArrayList("pageHistory", pageHistoryList);
|
||||
super.onSaveInstanceState(outState, outPersistentState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
SharedPreferences notificationPreferences = getApplicationContext()
|
||||
.getSharedPreferences("Notifications", MODE_PRIVATE);
|
||||
notificationPreferences.edit()
|
||||
.putString("current", "[]")
|
||||
.apply();
|
||||
|
||||
pushNotificationClient.clearNotifications(this);
|
||||
clearNotifications();
|
||||
|
||||
/* After editing a profile, the profile header in the navigation drawer needs to be
|
||||
* refreshed */
|
||||
|
@ -234,11 +236,50 @@ public class MainActivity extends BaseActivity {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
|
||||
ArrayList<Integer> pageHistoryList = new ArrayList<>();
|
||||
pageHistoryList.addAll(pageHistory);
|
||||
outState.putIntegerArrayList("pageHistory", pageHistoryList);
|
||||
super.onSaveInstanceState(outState, outPersistentState);
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == COMPOSE_RESULT && resultCode == ComposeActivity.RESULT_OK) {
|
||||
Intent intent = new Intent(TimelineReceiver.Types.STATUS_COMPOSED);
|
||||
LocalBroadcastManager.getInstance(getApplicationContext())
|
||||
.sendBroadcast(intent);
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (drawer != null && drawer.isDrawerOpen()) {
|
||||
drawer.closeDrawer();
|
||||
} else if (pageHistory.size() < 2) {
|
||||
super.onBackPressed();
|
||||
} else {
|
||||
pageHistory.pop();
|
||||
viewPager.setCurrentItem(pageHistory.peek());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_MENU: {
|
||||
if (drawer.isDrawerOpen()) {
|
||||
drawer.closeDrawer();
|
||||
} else {
|
||||
drawer.openDrawer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_SEARCH: {
|
||||
startActivity(new Intent(this, SearchActivity.class));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
// Fix for GitHub issues #190, #259 (MainActivity won't restart on screen rotation.)
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
private void tintTab(TabLayout.Tab tab, boolean tinted) {
|
||||
|
@ -465,51 +506,4 @@ public class MainActivity extends BaseActivity {
|
|||
private void onFetchUserInfoFailure(Exception exception) {
|
||||
Log.e(TAG, "Failed to fetch user info. " + exception.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == COMPOSE_RESULT && resultCode == ComposeActivity.RESULT_OK) {
|
||||
Intent intent = new Intent(TimelineReceiver.Types.STATUS_COMPOSED);
|
||||
LocalBroadcastManager.getInstance(getApplicationContext())
|
||||
.sendBroadcast(intent);
|
||||
}
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (drawer != null && drawer.isDrawerOpen()) {
|
||||
drawer.closeDrawer();
|
||||
} else if (pageHistory.size() < 2) {
|
||||
super.onBackPressed();
|
||||
} else {
|
||||
pageHistory.pop();
|
||||
viewPager.setCurrentItem(pageHistory.peek());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_MENU: {
|
||||
if (drawer.isDrawerOpen()) {
|
||||
drawer.closeDrawer();
|
||||
} else {
|
||||
drawer.openDrawer();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case KeyEvent.KEYCODE_SEARCH: {
|
||||
startActivity(new Intent(this, SearchActivity.class));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
// Fix for GitHub issues #190, #259 (MainActivity won't restart on screen rotation.)
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
|
@ -59,7 +59,8 @@ public class PreferencesActivity extends BaseActivity
|
|||
}
|
||||
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals("lightTheme")) {
|
||||
switch (key) {
|
||||
case "lightTheme": {
|
||||
themeSwitched = true;
|
||||
// recreate() could be used instead, but it doesn't have an animation B).
|
||||
Intent intent = getIntent();
|
||||
|
@ -70,14 +71,23 @@ public class PreferencesActivity extends BaseActivity
|
|||
startActivity(intent);
|
||||
finish();
|
||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
||||
} else if (key.equals("notificationsEnabled")) {
|
||||
boolean notificationsEnabled = sharedPreferences.getBoolean("notificationsEnabled", true);
|
||||
|
||||
if (notificationsEnabled) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/* 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.service;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.Spanned;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.json.SpannedTypeAdapter;
|
||||
import com.keylesspalace.tusky.json.StringWithEmoji;
|
||||
import com.keylesspalace.tusky.json.StringWithEmojiTypeAdapter;
|
||||
import com.keylesspalace.tusky.network.MastodonApi;
|
||||
import com.keylesspalace.tusky.util.OkHttpUtils;
|
||||
import com.keylesspalace.tusky.util.NotificationMaker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
public class PullNotificationService extends IntentService {
|
||||
public static final int NOTIFY_ID = 6; // This is an arbitrary number.
|
||||
|
||||
private MastodonApi mastodonApi;
|
||||
|
||||
public PullNotificationService() {
|
||||
super("Tusky Pull Notification Service");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(
|
||||
getApplicationContext());
|
||||
boolean enabled = preferences.getBoolean("notificationsEnabled", true);
|
||||
if (!enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
createMastodonApi();
|
||||
|
||||
mastodonApi.notifications(null, null, null).enqueue(new Callback<List<Notification>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<Notification>> call,
|
||||
Response<List<Notification>> response) {
|
||||
if (response.isSuccessful()) {
|
||||
onNotificationsReceived(response.body());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<Notification>> call, Throwable t) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void createMastodonApi() {
|
||||
SharedPreferences preferences = getSharedPreferences(
|
||||
getString(R.string.preferences_file_key), Context.MODE_PRIVATE);
|
||||
final String domain = preferences.getString("domain", null);
|
||||
final String accessToken = preferences.getString("accessToken", null);
|
||||
|
||||
OkHttpClient okHttpClient = OkHttpUtils.getCompatibleClientBuilder()
|
||||
.addInterceptor(new Interceptor() {
|
||||
@Override
|
||||
public okhttp3.Response intercept(Chain chain) throws IOException {
|
||||
Request originalRequest = chain.request();
|
||||
|
||||
Request.Builder builder = originalRequest.newBuilder()
|
||||
.header("Authorization", String.format("Bearer %s", accessToken));
|
||||
|
||||
Request newRequest = builder.build();
|
||||
|
||||
return chain.proceed(newRequest);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Spanned.class, new SpannedTypeAdapter())
|
||||
.registerTypeAdapter(StringWithEmoji.class, new StringWithEmojiTypeAdapter())
|
||||
.create();
|
||||
|
||||
Retrofit retrofit = new Retrofit.Builder()
|
||||
.baseUrl("https://" + domain)
|
||||
.client(okHttpClient)
|
||||
.addConverterFactory(GsonConverterFactory.create(gson))
|
||||
.build();
|
||||
|
||||
mastodonApi = retrofit.create(MastodonApi.class);
|
||||
}
|
||||
|
||||
private void onNotificationsReceived(List<Notification> notificationList) {
|
||||
SharedPreferences notificationsPreferences = getSharedPreferences(
|
||||
"Notifications", Context.MODE_PRIVATE);
|
||||
Set<String> currentIds = notificationsPreferences.getStringSet(
|
||||
"current_ids", new HashSet<String>());
|
||||
for (Notification notification : notificationList) {
|
||||
String id = notification.id;
|
||||
if (!currentIds.contains(id)) {
|
||||
currentIds.add(id);
|
||||
NotificationMaker.make(this, NOTIFY_ID, notification);
|
||||
}
|
||||
}
|
||||
notificationsPreferences.edit()
|
||||
.putStringSet("current_ids", currentIds)
|
||||
.apply();
|
||||
}
|
||||
}
|
|
@ -41,7 +41,7 @@ import com.squareup.picasso.Target;
|
|||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
class NotificationMaker {
|
||||
public class NotificationMaker {
|
||||
|
||||
public static final String TAG = "NotificationMaker";
|
||||
|
||||
|
|
27
app/src/main/res/values/array.xml
Normal file
27
app/src/main/res/values/array.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string-array name="pull_notification_check_interval_names">
|
||||
<item>5 minutes</item>
|
||||
<item>10 minutes</item>
|
||||
<item>15 minutes</item>
|
||||
<item>20 minutes</item>
|
||||
<item>25 minutes</item>
|
||||
<item>30 minutes</item>
|
||||
<item>45 minutes</item>
|
||||
<item>1 hour</item>
|
||||
<item>2 hours</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="pull_notification_check_intervals" inputType="integer">
|
||||
<item>5</item>
|
||||
<item>10</item>
|
||||
<item>15</item>
|
||||
<item>20</item>
|
||||
<item>25</item>
|
||||
<item>30</item>
|
||||
<item>45</item>
|
||||
<item>60</item>
|
||||
<item>120</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
|
@ -146,7 +146,8 @@
|
|||
|
||||
<string name="pref_title_notification_settings">Notifications</string>
|
||||
<string name="pref_title_edit_notification_settings">Edit Notifications</string>
|
||||
<string name="pref_title_notifications_enabled">Push notifications</string>
|
||||
<string name="pref_title_notifications_enabled">Notifications</string>
|
||||
<string name="pref_title_pull_notification_check_interval">Check Interval</string>
|
||||
<string name="pref_title_notification_alerts">Alerts</string>
|
||||
<string name="pref_title_notification_alert_sound">Notify with a sound</string>
|
||||
<string name="pref_title_notification_alert_vibrate">Notify with vibration</string>
|
||||
|
|
|
@ -54,6 +54,12 @@
|
|||
android:title="@string/pref_title_notifications_enabled"
|
||||
android:defaultValue="true" />
|
||||
|
||||
<ListPreference android:key="pullNotificationCheckInterval"
|
||||
android:title="@string/pref_title_pull_notification_check_interval"
|
||||
android:entries="@array/pull_notification_check_interval_names"
|
||||
android:entryValues="@array/pull_notification_check_intervals"
|
||||
android:defaultValue="15" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:dependency="notificationsEnabled"
|
||||
android:title="@string/pref_title_notification_filters">
|
||||
|
|
Loading…
Reference in a new issue