Add ComposeActivity tests. Add ServiceLocator (#542)

This commit is contained in:
Ivan Kupalov 2018-03-10 00:02:32 +03:00 committed by Konrad Pozniak
parent 4e617dccc7
commit 28e46c9cc0
18 changed files with 337 additions and 154 deletions

View file

@ -36,6 +36,11 @@ android {
androidExtensions { androidExtensions {
experimental = true experimental = true
} }
testOptions {
unitTests {
includeAndroidResources = true
}
}
} }
ext.supportLibraryVersion = '27.1.0' ext.supportLibraryVersion = '27.1.0'
@ -68,12 +73,15 @@ dependencies {
//room //room
implementation 'android.arch.persistence.room:runtime:1.0.0' implementation 'android.arch.persistence.room:runtime:1.0.0'
kapt 'android.arch.persistence.room:compiler:1.0.0' kapt 'android.arch.persistence.room:compiler:1.0.0'
testImplementation 'junit:junit:4.12'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
testImplementation 'junit:junit:4.12'
testImplementation "org.robolectric:robolectric:3.7.1"
testCompile "org.mockito:mockito-inline:2.15.0"
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
}) })
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
debugImplementation 'im.dino:dbinspector:3.4.1@aar' debugImplementation 'im.dino:dbinspector:3.4.1@aar'
} }

View file

@ -46,6 +46,7 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
import com.keylesspalace.tusky.entity.Relationship; import com.keylesspalace.tusky.entity.Relationship;
import com.keylesspalace.tusky.interfaces.ActionButtonActivity; import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
@ -193,7 +194,8 @@ public final class AccountActivity extends BaseActivity implements ActionButtonA
// Obtain information to fill out the profile. // Obtain information to fill out the profile.
obtainAccount(); obtainAccount();
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity activeAccount = TuskyApplication.getInstance(this).getServiceLocator()
.get(AccountManager.class).getActiveAccount();
if (accountId.equals(activeAccount.getAccountId())) { if (accountId.equals(activeAccount.getAccountId())) {
isSelf = true; isSelf = true;

View file

@ -34,6 +34,7 @@ import com.evernote.android.job.JobRequest;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.json.SpannedTypeAdapter; import com.keylesspalace.tusky.json.SpannedTypeAdapter;
import com.keylesspalace.tusky.network.AuthInterceptor; import com.keylesspalace.tusky.network.AuthInterceptor;
import com.keylesspalace.tusky.network.MastodonApi; import com.keylesspalace.tusky.network.MastodonApi;
@ -50,11 +51,15 @@ public abstract class BaseActivity extends AppCompatActivity {
public MastodonApi mastodonApi; public MastodonApi mastodonApi;
protected Dispatcher mastodonApiDispatcher; protected Dispatcher mastodonApiDispatcher;
private AccountManager accountManager;
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState) { protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
accountManager = TuskyApplication.getInstance(this).getServiceLocator()
.get(AccountManager.class);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
/* There isn't presently a way to globally change the theme of a whole application at /* There isn't presently a way to globally change the theme of a whole application at
@ -64,7 +69,7 @@ public abstract class BaseActivity extends AppCompatActivity {
ThemeUtils.setAppNightMode(theme); ThemeUtils.setAppNightMode(theme);
int style; int style;
switch(preferences.getString("statusTextSize", "medium")) { switch (preferences.getString("statusTextSize", "medium")) {
case "large": case "large":
style = R.style.TextSizeLarge; style = R.style.TextSizeLarge;
break; break;
@ -79,7 +84,7 @@ public abstract class BaseActivity extends AppCompatActivity {
} }
getTheme().applyStyle(style, false); getTheme().applyStyle(style, false);
if(redirectIfNotLoggedIn()) { if (redirectIfNotLoggedIn()) {
return; return;
} }
createMastodonApi(); createMastodonApi();
@ -119,8 +124,8 @@ public abstract class BaseActivity extends AppCompatActivity {
} }
protected String getBaseUrl() { protected String getBaseUrl() {
AccountEntity account = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity account = accountManager.getActiveAccount();
if(account != null) { if (account != null) {
return "https://" + account.getDomain(); return "https://" + account.getDomain();
} else { } else {
return ""; return "";
@ -138,7 +143,7 @@ public abstract class BaseActivity extends AppCompatActivity {
OkHttpClient.Builder okBuilder = OkHttpClient.Builder okBuilder =
OkHttpUtils.getCompatibleClientBuilder(preferences) OkHttpUtils.getCompatibleClientBuilder(preferences)
.addInterceptor(new AuthInterceptor()) .addInterceptor(new AuthInterceptor(accountManager))
.dispatcher(mastodonApiDispatcher); .dispatcher(mastodonApiDispatcher);
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
@ -155,7 +160,7 @@ public abstract class BaseActivity extends AppCompatActivity {
} }
protected boolean redirectIfNotLoggedIn() { protected boolean redirectIfNotLoggedIn() {
if (TuskyApplication.getAccountManager().getActiveAccount() == null) { if (accountManager.getActiveAccount() == null) {
Intent intent = new Intent(this, LoginActivity.class); Intent intent = new Intent(this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); startActivity(intent);

View file

@ -79,6 +79,7 @@ import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.keylesspalace.tusky.adapter.MentionAutoCompleteAdapter; import com.keylesspalace.tusky.adapter.MentionAutoCompleteAdapter;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.db.TootDao; import com.keylesspalace.tusky.db.TootDao;
import com.keylesspalace.tusky.db.TootEntity; import com.keylesspalace.tusky.db.TootEntity;
import com.keylesspalace.tusky.entity.Account; import com.keylesspalace.tusky.entity.Account;
@ -160,7 +161,7 @@ public final class ComposeActivity extends BaseActivity
// this only exists when a status is trying to be sent, but uploads are still occurring // this only exists when a status is trying to be sent, but uploads are still occurring
private ProgressDialog finishingUploadDialog; private ProgressDialog finishingUploadDialog;
private String inReplyToId; private String inReplyToId;
private ArrayList<QueuedMedia> mediaQueued; private List<QueuedMedia> mediaQueued = new ArrayList<>();
private CountUpDownLatch waitForMediaLatch; private CountUpDownLatch waitForMediaLatch;
private boolean showMarkSensitive; private boolean showMarkSensitive;
private Status.Visibility statusVisibility; // The current values of the options that will be applied private Status.Visibility statusVisibility; // The current values of the options that will be applied
@ -205,7 +206,8 @@ public final class ComposeActivity extends BaseActivity
} }
// setup the account image // setup the account image
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity activeAccount = TuskyApplication.getInstance(this).getServiceLocator()
.get(AccountManager.class).getActiveAccount();
if (activeAccount != null) { if (activeAccount != null) {
@ -409,7 +411,6 @@ public final class ComposeActivity extends BaseActivity
} }
// Initialise the empty media queue state. // Initialise the empty media queue state.
mediaQueued = new ArrayList<>();
waitForMediaLatch = new CountUpDownLatch(); waitForMediaLatch = new CountUpDownLatch();
statusAlreadyInFlight = false; statusAlreadyInFlight = false;

View file

@ -31,6 +31,7 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.EditText import android.widget.EditText
import android.widget.TextView import android.widget.TextView
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.entity.AccessToken import com.keylesspalace.tusky.entity.AccessToken
import com.keylesspalace.tusky.entity.AppCredentials import com.keylesspalace.tusky.entity.AppCredentials
import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.network.MastodonApi
@ -88,7 +89,7 @@ class LoginActivity : AppCompatActivity() {
textView.movementMethod = LinkMovementMethod.getInstance() textView.movementMethod = LinkMovementMethod.getInstance()
} }
if(isAdditionalLogin()) { if (isAdditionalLogin()) {
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false) supportActionBar?.setDisplayShowTitleEnabled(false)
@ -99,7 +100,7 @@ class LoginActivity : AppCompatActivity() {
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId == android.R.id.home) { if (item.itemId == android.R.id.home) {
onBackPressed() onBackPressed()
return true return true
} }
@ -281,7 +282,7 @@ class LoginActivity : AppCompatActivity() {
} }
} }
private fun isAdditionalLogin() : Boolean { private fun isAdditionalLogin(): Boolean {
return intent.getBooleanExtra(LOGIN_MODE, false) return intent.getBooleanExtra(LOGIN_MODE, false)
} }
@ -289,7 +290,9 @@ class LoginActivity : AppCompatActivity() {
setLoading(true) setLoading(true)
TuskyApplication.getAccountManager().addAccount(accessToken, domain) TuskyApplication.getInstance(this).serviceLocator
.get(AccountManager::class.java)
.addAccount(accessToken, domain)
val intent = Intent(this, MainActivity::class.java) val intent = Intent(this, MainActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK

View file

@ -84,6 +84,8 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
private static int COMPOSE_RESULT = 1; private static int COMPOSE_RESULT = 1;
AccountManager accountManager;
private FloatingActionButton composeButton; private FloatingActionButton composeButton;
private AccountHeader headerResult; private AccountHeader headerResult;
private Drawer drawer; private Drawer drawer;
@ -97,16 +99,19 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
int tabPosition = 0; int tabPosition = 0;
accountManager = TuskyApplication.getInstance(this).getServiceLocator()
.get(AccountManager.class);
if (intent != null) { if (intent != null) {
long accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1); long accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1);
if(accountId != -1) { if (accountId != -1) {
// user clicked a notification, show notification tab and switch user if necessary // user clicked a notification, show notification tab and switch user if necessary
tabPosition = 1; tabPosition = 1;
AccountEntity account = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity account = accountManager.getActiveAccount();
if (account == null || accountId != account.getId()) { if (account == null || accountId != account.getId()) {
TuskyApplication.getAccountManager().setActiveAccount(accountId); accountManager.setActiveAccount(accountId);
} }
} }
} }
@ -180,7 +185,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
tintTab(tab, true); tintTab(tab, true);
if(tab.getPosition() == 1) { if (tab.getPosition() == 1) {
NotificationHelper.clearNotificationsForActiveAccount(MainActivity.this); NotificationHelper.clearNotificationsForActiveAccount(MainActivity.this);
} }
} }
@ -191,7 +196,8 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
} }
@Override @Override
public void onTabReselected(TabLayout.Tab tab) { } public void onTabReselected(TabLayout.Tab tab) {
}
}); });
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
@ -385,7 +391,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
}) })
.build(); .build();
if(BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
IDrawerItem debugItem = new SecondaryDrawerItem() IDrawerItem debugItem = new SecondaryDrawerItem()
.withIdentifier(1337) .withIdentifier(1337)
.withName("debug") .withName("debug")
@ -399,7 +405,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
} }
private boolean handleProfileClick(IProfile profile, boolean current) { private boolean handleProfileClick(IProfile profile, boolean current) {
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity activeAccount = accountManager.getActiveAccount();
//open profile when active image was clicked //open profile when active image was clicked
if (current && activeAccount != null) { if (current && activeAccount != null) {
@ -409,7 +415,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
return true; return true;
} }
//open LoginActivity to add new account //open LoginActivity to add new account
if(profile.getIdentifier() == DRAWER_ITEM_ADD_ACCOUNT ) { if (profile.getIdentifier() == DRAWER_ITEM_ADD_ACCOUNT) {
startActivity(LoginActivity.getIntent(this, true)); startActivity(LoginActivity.getIntent(this, true));
return true; return true;
} }
@ -420,7 +426,7 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
private void changeAccount(long newSelectedId) { private void changeAccount(long newSelectedId) {
TuskyApplication.getAccountManager().setActiveAccount(newSelectedId); accountManager.setActiveAccount(newSelectedId);
Intent intent = new Intent(this, MainActivity.class); Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@ -432,22 +438,22 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
private void logout() { private void logout() {
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity activeAccount = accountManager.getActiveAccount();
if(activeAccount != null) { if (activeAccount != null) {
new AlertDialog.Builder(this) new AlertDialog.Builder(this)
.setTitle(R.string.action_logout) .setTitle(R.string.action_logout)
.setMessage(getString(R.string.action_logout_confirm, activeAccount.getFullName())) .setMessage(getString(R.string.action_logout_confirm, activeAccount.getFullName()))
.setPositiveButton(android.R.string.yes, (dialog, which) -> { .setPositiveButton(android.R.string.yes, (dialog, which) -> {
;
AccountManager accountManager = TuskyApplication.getAccountManager();
NotificationHelper.deleteNotificationChannelsForAccount(accountManager.getActiveAccount(), MainActivity.this); NotificationHelper.deleteNotificationChannelsForAccount(accountManager.getActiveAccount(), MainActivity.this);
AccountEntity newAccount = accountManager.logActiveAccountOut(); AccountEntity newAccount = accountManager.logActiveAccountOut();
if (!NotificationHelper.areNotificationsEnabled(MainActivity.this)) disablePushNotifications(); if (!NotificationHelper.areNotificationsEnabled(MainActivity.this))
disablePushNotifications();
Intent intent; Intent intent;
if (newAccount == null) { if (newAccount == null) {
@ -492,11 +498,9 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
.placeholder(R.drawable.account_header_default) .placeholder(R.drawable.account_header_default)
.into(background); .into(background);
AccountManager am = TuskyApplication.getAccountManager(); accountManager.updateActiveAccount(me);
am.updateActiveAccount(me); NotificationHelper.createNotificationChannelsForAccount(accountManager.getActiveAccount(), this);
NotificationHelper.createNotificationChannelsForAccount(am.getActiveAccount(), this);
// Show follow requests in the menu, if this is a locked account. // Show follow requests in the menu, if this is a locked account.
if (me.getLocked() && drawer.getDrawerItem(DRAWER_ITEM_FOLLOW_REQUESTS) == null) { if (me.getLocked() && drawer.getDrawerItem(DRAWER_ITEM_FOLLOW_REQUESTS) == null) {
@ -513,19 +517,18 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity {
} }
private void updateProfiles() { private void updateProfiles() {
AccountManager am = TuskyApplication.getAccountManager();
List<AccountEntity> allAccounts = am.getAllAccountsOrderedByActive(); List<AccountEntity> allAccounts = accountManager.getAllAccountsOrderedByActive();
//remove profiles before adding them again to avoid duplicates //remove profiles before adding them again to avoid duplicates
List<IProfile> profiles = new ArrayList<>(headerResult.getProfiles()); List<IProfile> profiles = new ArrayList<>(headerResult.getProfiles());
for(IProfile profile: profiles) { for (IProfile profile : profiles) {
if(profile.getIdentifier() != DRAWER_ITEM_ADD_ACCOUNT) { if (profile.getIdentifier() != DRAWER_ITEM_ADD_ACCOUNT) {
headerResult.removeProfile(profile); headerResult.removeProfile(profile);
} }
} }
for(AccountEntity acc: allAccounts) { for (AccountEntity acc : allAccounts) {
headerResult.addProfiles( headerResult.addProfiles(
new ProfileDrawerItem() new ProfileDrawerItem()
.withName(acc.getDisplayName()) .withName(acc.getDisplayName())

View file

@ -27,6 +27,7 @@ import com.evernote.android.job.JobCreator;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.entity.Notification; import com.keylesspalace.tusky.entity.Notification;
import com.keylesspalace.tusky.json.SpannedTypeAdapter; import com.keylesspalace.tusky.json.SpannedTypeAdapter;
import com.keylesspalace.tusky.network.MastodonApi; import com.keylesspalace.tusky.network.MastodonApi;
@ -101,14 +102,16 @@ public final class NotificationPullJobCreator implements JobCreator {
@Override @Override
protected Result onRunJob(@NonNull Params params) { protected Result onRunJob(@NonNull Params params) {
List<AccountEntity> accountList = new ArrayList<>(TuskyApplication.getAccountManager().getAllAccountsOrderedByActive()); AccountManager accountManager = TuskyApplication.getInstance(context).getServiceLocator()
.get(AccountManager.class);
List<AccountEntity> accountList = new ArrayList<>(accountManager.getAllAccountsOrderedByActive());
for(AccountEntity account: accountList) { for (AccountEntity account : accountList) {
if(account.getNotificationsEnabled()) { if (account.getNotificationsEnabled()) {
MastodonApi api = createMastodonApi(account.getDomain(), context); MastodonApi api = createMastodonApi(account.getDomain(), context);
try { try {
Log.d(TAG, "getting Notifications for "+account.getFullName()); Log.d(TAG, "getting Notifications for " + account.getFullName());
Response<List<Notification>> notifications = Response<List<Notification>> notifications =
api.notificationsWithAuth(String.format("Bearer %s", account.getAccessToken())).execute(); api.notificationsWithAuth(String.format("Bearer %s", account.getAccessToken())).execute();
if (notifications.isSuccessful()) { if (notifications.isSuccessful()) {
@ -136,11 +139,11 @@ public final class NotificationPullJobCreator implements JobCreator {
BigInteger newestId = BigInteger.ZERO; BigInteger newestId = BigInteger.ZERO;
for(Notification notification: notificationList){ for (Notification notification : notificationList) {
BigInteger currentId = new BigInteger(notification.getId()); BigInteger currentId = new BigInteger(notification.getId());
if(isBiggerThan(currentId, newestId)) { if (isBiggerThan(currentId, newestId)) {
newestId = currentId; newestId = currentId;
} }
@ -150,13 +153,13 @@ public final class NotificationPullJobCreator implements JobCreator {
} }
account.setLastNotificationId(newestId.toString()); account.setLastNotificationId(newestId.toString());
TuskyApplication.getAccountManager().saveAccount(account); TuskyApplication.getInstance(context).getServiceLocator()
.get(AccountManager.class).saveAccount(account);
} }
private boolean isBiggerThan(BigInteger newId, BigInteger lastShownNotificationId) { private boolean isBiggerThan(BigInteger newId, BigInteger lastShownNotificationId) {
return lastShownNotificationId.compareTo(newId) == - 1; return lastShownNotificationId.compareTo(newId) == -1;
} }
} }
} }

View file

@ -20,6 +20,7 @@ import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.util.NotificationHelper; import com.keylesspalace.tusky.util.NotificationHelper;
public class SplashActivity extends AppCompatActivity { public class SplashActivity extends AppCompatActivity {
@ -32,7 +33,8 @@ public class SplashActivity extends AppCompatActivity {
NotificationHelper.deleteLegacyNotificationChannels(this); NotificationHelper.deleteLegacyNotificationChannels(this);
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity activeAccount = TuskyApplication.getInstance(this).getServiceLocator()
.get(AccountManager.class).getActiveAccount();
Intent intent; Intent intent;
if (activeAccount != null) { if (activeAccount != null) {

View file

@ -21,6 +21,7 @@ import android.arch.persistence.room.Room;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatDelegate; import android.support.v7.app.AppCompatDelegate;
import com.evernote.android.job.JobManager; import com.evernote.android.job.JobManager;
@ -35,7 +36,7 @@ public class TuskyApplication extends Application {
public static final String APP_THEME_DEFAULT = ThemeUtils.THEME_NIGHT; public static final String APP_THEME_DEFAULT = ThemeUtils.THEME_NIGHT;
private static AppDatabase db; private static AppDatabase db;
private static AccountManager accountManager; private AccountManager accountManager;
public static AppDatabase getDB() { public static AppDatabase getDB() {
return db; return db;
@ -43,24 +44,33 @@ public class TuskyApplication extends Application {
private static UiModeManager uiModeManager; private static UiModeManager uiModeManager;
public static UiModeManager getUiModeManager() { return uiModeManager; } public static UiModeManager getUiModeManager() {
return uiModeManager;
}
public static TuskyApplication getInstance(@NonNull Context context) {
return (TuskyApplication) context.getApplicationContext();
}
private ServiceLocator serviceLocator;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
// Initialize Picasso configuration initPicasso();
Picasso.Builder builder = new Picasso.Builder(this);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
builder.downloader(new OkHttp3Downloader(OkHttpUtils.getCompatibleClient(preferences)));
if (BuildConfig.DEBUG) {
builder.listener((picasso, uri, exception) -> exception.printStackTrace());
}
try { serviceLocator = new ServiceLocator() {
Picasso.setSingletonInstance(builder.build()); @Override
} catch (IllegalStateException e) { public <T> T get(Class<T> clazz) {
throw new RuntimeException(e); if (clazz.equals(AccountManager.class)) {
} //noinspection unchecked
return (T) accountManager;
} else {
throw new IllegalArgumentException("Unknown service " + clazz);
}
}
};
db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tuskyDB") db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "tuskyDB")
.allowMainThreadQueries() .allowMainThreadQueries()
@ -69,7 +79,7 @@ public class TuskyApplication extends Application {
JobManager.create(this).addJobCreator(new NotificationPullJobCreator(this)); JobManager.create(this).addJobCreator(new NotificationPullJobCreator(this));
uiModeManager = (UiModeManager)getSystemService(Context.UI_MODE_SERVICE); uiModeManager = (UiModeManager) getSystemService(Context.UI_MODE_SERVICE);
//necessary for Android < APi 21 //necessary for Android < APi 21
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
@ -77,8 +87,26 @@ public class TuskyApplication extends Application {
accountManager = new AccountManager(); accountManager = new AccountManager();
} }
public static AccountManager getAccountManager() { protected void initPicasso() {
return accountManager; // Initialize Picasso configuration
Picasso.Builder builder = new Picasso.Builder(this);
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
builder.downloader(new OkHttp3Downloader(OkHttpUtils.getCompatibleClient(preferences)));
if (BuildConfig.DEBUG) {
builder.listener((picasso, uri, exception) -> exception.printStackTrace());
}
try {
Picasso.setSingletonInstance(builder.build());
} catch (IllegalStateException e) {
throw new RuntimeException(e);
}
} }
} public ServiceLocator getServiceLocator() {
return serviceLocator;
}
public interface ServiceLocator {
<T> T get(Class<T> clazz);
}
}

View file

@ -192,10 +192,12 @@ public class NotificationsFragment extends SFragment implements
TabLayout layout = activity.findViewById(R.id.tab_layout); TabLayout layout = activity.findViewById(R.id.tab_layout);
onTabSelectedListener = new TabLayout.OnTabSelectedListener() { onTabSelectedListener = new TabLayout.OnTabSelectedListener() {
@Override @Override
public void onTabSelected(TabLayout.Tab tab) {} public void onTabSelected(TabLayout.Tab tab) {
}
@Override @Override
public void onTabUnselected(TabLayout.Tab tab) {} public void onTabUnselected(TabLayout.Tab tab) {
}
@Override @Override
public void onTabReselected(TabLayout.Tab tab) { public void onTabReselected(TabLayout.Tab tab) {
@ -281,7 +283,7 @@ public class NotificationsFragment extends SFragment implements
status.getReblog().setReblogged(reblog); status.getReblog().setReblogged(reblog);
} }
NotificationViewData.Concrete viewdata = (NotificationViewData.Concrete)notifications.getPairedItem(position); NotificationViewData.Concrete viewdata = (NotificationViewData.Concrete) notifications.getPairedItem(position);
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder(viewdata.getStatusViewData()); StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder(viewdata.getStatusViewData());
viewDataBuilder.setReblogged(reblog); viewDataBuilder.setReblogged(reblog);
@ -318,7 +320,7 @@ public class NotificationsFragment extends SFragment implements
status.getReblog().setFavourited(favourite); status.getReblog().setFavourited(favourite);
} }
NotificationViewData.Concrete viewdata = (NotificationViewData.Concrete)notifications.getPairedItem(position); NotificationViewData.Concrete viewdata = (NotificationViewData.Concrete) notifications.getPairedItem(position);
StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder(viewdata.getStatusViewData()); StatusViewData.Builder viewDataBuilder = new StatusViewData.Builder(viewdata.getStatusViewData());
viewDataBuilder.setFavourited(favourite); viewDataBuilder.setFavourited(favourite);
@ -587,13 +589,14 @@ public class NotificationsFragment extends SFragment implements
} }
private void saveNewestNotificationId(List<Notification> notifications) { private void saveNewestNotificationId(List<Notification> notifications) {
AccountManager accountManager = TuskyApplication.getAccountManager(); AccountManager accountManager = TuskyApplication.getInstance(getContext())
.getServiceLocator().get(AccountManager.class);
AccountEntity account = accountManager.getActiveAccount(); AccountEntity account = accountManager.getActiveAccount();
BigInteger lastNoti = new BigInteger(account.getLastNotificationId()); BigInteger lastNoti = new BigInteger(account.getLastNotificationId());
for (Notification noti: notifications) { for (Notification noti : notifications) {
BigInteger a = new BigInteger(noti.getId()); BigInteger a = new BigInteger(noti.getId());
if(isBiggerThan(a, lastNoti)) { if (isBiggerThan(a, lastNoti)) {
lastNoti = a; lastNoti = a;
} }
} }
@ -606,7 +609,7 @@ public class NotificationsFragment extends SFragment implements
private boolean isBiggerThan(BigInteger newId, BigInteger lastShownNotificationId) { private boolean isBiggerThan(BigInteger newId, BigInteger lastShownNotificationId) {
return lastShownNotificationId.compareTo(newId) == - 1; return lastShownNotificationId.compareTo(newId) == -1;
} }
private void update(@Nullable List<Notification> newNotifications, @Nullable String fromId, private void update(@Nullable List<Notification> newNotifications, @Nullable String fromId,

View file

@ -30,6 +30,7 @@ import com.keylesspalace.tusky.PreferencesActivity;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;
import com.keylesspalace.tusky.TuskyApplication; import com.keylesspalace.tusky.TuskyApplication;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
public class PreferencesFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { public class PreferencesFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
SharedPreferences sharedPreferences; SharedPreferences sharedPreferences;
@ -47,20 +48,26 @@ public class PreferencesFragment extends PreferenceFragment implements SharedPre
return fragment; return fragment;
} }
private AccountManager accountManager;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
accountManager = TuskyApplication.getInstance(getActivity()).getServiceLocator()
.get(AccountManager.class);
int preference = getArguments().getInt("preference"); int preference = getArguments().getInt("preference");
addPreferencesFromResource(preference); addPreferencesFromResource(preference);
Preference notificationPreferences = findPreference("notificationPreferences"); Preference notificationPreferences = findPreference("notificationPreferences");
if(notificationPreferences != null) { if (notificationPreferences != null) {
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity activeAccount = accountManager.getActiveAccount();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O && activeAccount != null) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O && activeAccount != null) {
notificationPreferences.setSummary(getString(R.string.pref_summary_notifications, activeAccount.getFullName())); notificationPreferences.setSummary(getString(R.string.pref_summary_notifications, activeAccount.getFullName()));
@ -92,8 +99,8 @@ public class PreferencesFragment extends PreferenceFragment implements SharedPre
} }
} }
Preference timelineFilterPreferences = findPreference("timelineFilterPreferences"); Preference timelineFilterPreferences = findPreference("timelineFilterPreferences");
if(timelineFilterPreferences != null) { if (timelineFilterPreferences != null) {
timelineFilterPreferences.setOnPreferenceClickListener(pref -> { timelineFilterPreferences.setOnPreferenceClickListener(pref -> {
PreferencesActivity activity = (PreferencesActivity) getActivity(); PreferencesActivity activity = (PreferencesActivity) getActivity();
if (activity != null) { if (activity != null) {
@ -104,8 +111,8 @@ public class PreferencesFragment extends PreferenceFragment implements SharedPre
}); });
} }
Preference httpProxyPreferences = findPreference("httpProxyPreferences"); Preference httpProxyPreferences = findPreference("httpProxyPreferences");
if(httpProxyPreferences != null) { if (httpProxyPreferences != null) {
httpProxyPreferences.setOnPreferenceClickListener(pref -> { httpProxyPreferences.setOnPreferenceClickListener(pref -> {
PreferencesActivity activity = (PreferencesActivity) getActivity(); PreferencesActivity activity = (PreferencesActivity) getActivity();
if (activity != null) { if (activity != null) {
@ -117,11 +124,11 @@ public class PreferencesFragment extends PreferenceFragment implements SharedPre
}); });
} }
if(preference == R.xml.notification_preferences) { if (preference == R.xml.notification_preferences) {
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity activeAccount = accountManager.getActiveAccount();
if(activeAccount != null) { if (activeAccount != null) {
CheckBoxPreference notificationPref = (CheckBoxPreference) findPreference("notificationsEnabled"); CheckBoxPreference notificationPref = (CheckBoxPreference) findPreference("notificationsEnabled");
notificationPref.setChecked(activeAccount.getNotificationsEnabled()); notificationPref.setChecked(activeAccount.getNotificationsEnabled());
@ -188,10 +195,10 @@ public class PreferencesFragment extends PreferenceFragment implements SharedPre
default: default:
} }
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); AccountEntity activeAccount = accountManager.getActiveAccount();
if(activeAccount != null) { if (activeAccount != null) {
switch(key) { switch (key) {
case "notificationsEnabled": case "notificationsEnabled":
activeAccount.setNotificationsEnabled(sharedPreferences.getBoolean(key, true)); activeAccount.setNotificationsEnabled(sharedPreferences.getBoolean(key, true));
break; break;
@ -217,7 +224,7 @@ public class PreferencesFragment extends PreferenceFragment implements SharedPre
activeAccount.setNotificationLight(sharedPreferences.getBoolean(key, true)); activeAccount.setNotificationLight(sharedPreferences.getBoolean(key, true));
break; break;
} }
TuskyApplication.getAccountManager().saveAccount(activeAccount); accountManager.saveAccount(activeAccount);
} }

View file

@ -41,6 +41,7 @@ import com.keylesspalace.tusky.ViewTagActivity;
import com.keylesspalace.tusky.ViewThreadActivity; import com.keylesspalace.tusky.ViewThreadActivity;
import com.keylesspalace.tusky.ViewVideoActivity; import com.keylesspalace.tusky.ViewVideoActivity;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import com.keylesspalace.tusky.entity.Attachment; import com.keylesspalace.tusky.entity.Attachment;
import com.keylesspalace.tusky.entity.Relationship; import com.keylesspalace.tusky.entity.Relationship;
import com.keylesspalace.tusky.entity.Status; import com.keylesspalace.tusky.entity.Status;
@ -71,19 +72,14 @@ public abstract class SFragment extends BaseFragment implements AdapterItemRemov
protected MastodonApi mastodonApi; protected MastodonApi mastodonApi;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onActivityCreated(savedInstanceState);
AccountEntity activeAccount = TuskyApplication.getInstance(getContext()).getServiceLocator()
AccountEntity activeAccount = TuskyApplication.getAccountManager().getActiveAccount(); .get(AccountManager.class).getActiveAccount();
if(activeAccount != null) { if (activeAccount != null) {
loggedInAccountId = activeAccount.getAccountId(); loggedInAccountId = activeAccount.getAccountId();
loggedInUsername = activeAccount.getUsername(); loggedInUsername = activeAccount.getUsername();
} }
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
BaseActivity activity = (BaseActivity) getActivity(); BaseActivity activity = (BaseActivity) getActivity();
mastodonApi = activity.mastodonApi; mastodonApi = activity.mastodonApi;
} }
@ -153,10 +149,12 @@ public abstract class SFragment extends BaseFragment implements AdapterItemRemov
Call<Relationship> call = mastodonApi.muteAccount(id); Call<Relationship> call = mastodonApi.muteAccount(id);
call.enqueue(new Callback<Relationship>() { call.enqueue(new Callback<Relationship>() {
@Override @Override
public void onResponse(@NonNull Call<Relationship> call, @NonNull Response<Relationship> response) {} public void onResponse(@NonNull Call<Relationship> call, @NonNull Response<Relationship> response) {
}
@Override @Override
public void onFailure(@NonNull Call<Relationship> call, @NonNull Throwable t) {} public void onFailure(@NonNull Call<Relationship> call, @NonNull Throwable t) {
}
}); });
callList.add(call); callList.add(call);
Intent intent = new Intent(TimelineReceiver.Types.MUTE_ACCOUNT); Intent intent = new Intent(TimelineReceiver.Types.MUTE_ACCOUNT);
@ -169,10 +167,12 @@ public abstract class SFragment extends BaseFragment implements AdapterItemRemov
Call<Relationship> call = mastodonApi.blockAccount(id); Call<Relationship> call = mastodonApi.blockAccount(id);
call.enqueue(new Callback<Relationship>() { call.enqueue(new Callback<Relationship>() {
@Override @Override
public void onResponse(@NonNull Call<Relationship> call, @NonNull retrofit2.Response<Relationship> response) {} public void onResponse(@NonNull Call<Relationship> call, @NonNull retrofit2.Response<Relationship> response) {
}
@Override @Override
public void onFailure(@NonNull Call<Relationship> call, @NonNull Throwable t) {} public void onFailure(@NonNull Call<Relationship> call, @NonNull Throwable t) {
}
}); });
callList.add(call); callList.add(call);
Intent intent = new Intent(TimelineReceiver.Types.BLOCK_ACCOUNT); Intent intent = new Intent(TimelineReceiver.Types.BLOCK_ACCOUNT);
@ -185,10 +185,12 @@ public abstract class SFragment extends BaseFragment implements AdapterItemRemov
Call<ResponseBody> call = mastodonApi.deleteStatus(id); Call<ResponseBody> call = mastodonApi.deleteStatus(id);
call.enqueue(new Callback<ResponseBody>() { call.enqueue(new Callback<ResponseBody>() {
@Override @Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {} public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
}
@Override @Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {} public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
}
}); });
callList.add(call); callList.add(call);
} }
@ -275,7 +277,7 @@ public abstract class SFragment extends BaseFragment implements AdapterItemRemov
ViewCompat.setTransitionName(view, url); ViewCompat.setTransitionName(view, url);
ActivityOptionsCompat options = ActivityOptionsCompat options =
ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(), ActivityOptionsCompat.makeSceneTransitionAnimation(getActivity(),
view, url); view, url);
startActivity(intent, options.toBundle()); startActivity(intent, options.toBundle());
} else { } else {
startActivity(intent); startActivity(intent);
@ -318,7 +320,7 @@ public abstract class SFragment extends BaseFragment implements AdapterItemRemov
} }
protected void openReportPage(String accountId, String accountUsername, String statusId, protected void openReportPage(String accountId, String accountUsername, String statusId,
Spanned statusContent) { Spanned statusContent) {
Intent intent = new Intent(getContext(), ReportActivity.class); Intent intent = new Intent(getContext(), ReportActivity.class);
intent.putExtra("account_id", accountId); intent.putExtra("account_id", accountId);
intent.putExtra("account_username", accountUsername); intent.putExtra("account_username", accountUsername);

View file

@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
import com.keylesspalace.tusky.TuskyApplication; import com.keylesspalace.tusky.TuskyApplication;
import com.keylesspalace.tusky.db.AccountEntity; import com.keylesspalace.tusky.db.AccountEntity;
import com.keylesspalace.tusky.db.AccountManager;
import java.io.IOException; import java.io.IOException;
@ -17,14 +18,17 @@ import okhttp3.Response;
public final class AuthInterceptor implements Interceptor { public final class AuthInterceptor implements Interceptor {
public AuthInterceptor() { } AccountManager accountManager;
public AuthInterceptor(AccountManager accountManager) {
this.accountManager = accountManager;
}
@Override @Override
public Response intercept(@NonNull Chain chain) throws IOException { public Response intercept(@NonNull Chain chain) throws IOException {
AccountEntity currentAccount = TuskyApplication.getAccountManager().getActiveAccount();
Request originalRequest = chain.request(); Request originalRequest = chain.request();
AccountEntity currentAccount = accountManager.getActiveAccount();
Request.Builder builder = originalRequest.newBuilder(); Request.Builder builder = originalRequest.newBuilder();
if (currentAccount != null) { if (currentAccount != null) {

View file

@ -20,6 +20,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import com.keylesspalace.tusky.TuskyApplication import com.keylesspalace.tusky.TuskyApplication
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.util.NotificationHelper import com.keylesspalace.tusky.util.NotificationHelper
class NotificationClearBroadcastReceiver : BroadcastReceiver() { class NotificationClearBroadcastReceiver : BroadcastReceiver() {
@ -27,7 +28,8 @@ class NotificationClearBroadcastReceiver : BroadcastReceiver() {
val accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1) val accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1)
val accountManager = TuskyApplication.getAccountManager() val accountManager = TuskyApplication.getInstance(context)
.serviceLocator.get(AccountManager::class.java)
val account = accountManager.getAccountById(accountId) val account = accountManager.getAccountById(accountId)
if (account != null) { if (account != null) {
account.activeNotifications = "[]" account.activeNotifications = "[]"

View file

@ -50,12 +50,16 @@ import java.util.List;
public class NotificationHelper { public class NotificationHelper {
/** constants used in Intents */ /**
* constants used in Intents
*/
public static final String ACCOUNT_ID = "account_id"; public static final String ACCOUNT_ID = "account_id";
private static final String TAG = "NotificationHelper"; private static final String TAG = "NotificationHelper";
/** notification channels used on Android O+ **/ /**
* notification channels used on Android O+
**/
private static final String CHANNEL_MENTION = "CHANNEL_MENTION"; private static final String CHANNEL_MENTION = "CHANNEL_MENTION";
private static final String CHANNEL_FOLLOW = "CHANNEL_FOLLOW"; private static final String CHANNEL_FOLLOW = "CHANNEL_FOLLOW";
private static final String CHANNEL_BOOST = "CHANNEL_BOOST"; private static final String CHANNEL_BOOST = "CHANNEL_BOOST";
@ -65,9 +69,9 @@ public class NotificationHelper {
* Takes a given Mastodon notification and either creates a new Android notification or updates * 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. * the state of the existing notification to reflect the new interaction.
* *
* @param context to access application preferences and services * @param context to access application preferences and services
* @param body a new Mastodon notification * @param body a new Mastodon notification
* @param account the account for which the notification should be shown * @param account the account for which the notification should be shown
*/ */
public static void make(final Context context, Notification body, AccountEntity account) { public static void make(final Context context, Notification body, AccountEntity account) {
@ -110,12 +114,12 @@ public class NotificationHelper {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(MainActivity.class); stackBuilder.addParentStack(MainActivity.class);
stackBuilder.addNextIntent(resultIntent); stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent((int)account.getId(), PendingIntent resultPendingIntent = stackBuilder.getPendingIntent((int) account.getId(),
PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent.FLAG_UPDATE_CURRENT);
Intent deleteIntent = new Intent(context, NotificationClearBroadcastReceiver.class); Intent deleteIntent = new Intent(context, NotificationClearBroadcastReceiver.class);
deleteIntent.putExtra(ACCOUNT_ID, account.getId()); deleteIntent.putExtra(ACCOUNT_ID, account.getId());
PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, (int)account.getId(), deleteIntent, PendingIntent deletePendingIntent = PendingIntent.getBroadcast(context, (int) account.getId(), deleteIntent,
PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent.FLAG_UPDATE_CURRENT);
final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getChannelId(account, body)) final NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getChannelId(account, body))
@ -131,7 +135,7 @@ public class NotificationHelper {
builder.setContentTitle(titleForType(context, body)) builder.setContentTitle(titleForType(context, body))
.setContentText(bodyForType(body)); .setContentText(bodyForType(body));
if(body.getType() == Notification.Type.MENTION) { if (body.getType() == Notification.Type.MENTION) {
builder.setStyle(new NotificationCompat.BigTextStyle() builder.setStyle(new NotificationCompat.BigTextStyle()
.bigText(bodyForType(body))); .bigText(bodyForType(body)));
} }
@ -171,7 +175,7 @@ public class NotificationHelper {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//noinspection ConstantConditions //noinspection ConstantConditions
notificationManager.notify((int)account.getId(), builder.build()); notificationManager.notify((int) account.getId(), builder.build());
} }
public static void createNotificationChannelsForAccount(AccountEntity account, Context context) { public static void createNotificationChannelsForAccount(AccountEntity account, Context context) {
@ -180,10 +184,10 @@ public class NotificationHelper {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
String[] channelIds = new String[]{ String[] channelIds = new String[]{
CHANNEL_MENTION+account.getIdentifier(), CHANNEL_MENTION + account.getIdentifier(),
CHANNEL_FOLLOW+account.getIdentifier(), CHANNEL_FOLLOW + account.getIdentifier(),
CHANNEL_BOOST+account.getIdentifier(), CHANNEL_BOOST + account.getIdentifier(),
CHANNEL_FAVOURITE+account.getIdentifier()}; CHANNEL_FAVOURITE + account.getIdentifier()};
int[] channelNames = { int[] channelNames = {
R.string.notification_channel_mention_name, R.string.notification_channel_mention_name,
R.string.notification_channel_follow_name, R.string.notification_channel_follow_name,
@ -252,15 +256,15 @@ public class NotificationHelper {
} }
public static boolean areNotificationsEnabled(Context context) { public static boolean areNotificationsEnabled(Context context) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// on Android >= O, notifications are enabled, if at least one channel is enabled // on Android >= O, notifications are enabled, if at least one channel is enabled
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//noinspection ConstantConditions //noinspection ConstantConditions
if(notificationManager.areNotificationsEnabled()) { if (notificationManager.areNotificationsEnabled()) {
for(NotificationChannel channel: notificationManager.getNotificationChannels()) { for (NotificationChannel channel : notificationManager.getNotificationChannels()) {
if(channel.getImportance() > NotificationManager.IMPORTANCE_NONE) { if (channel.getImportance() > NotificationManager.IMPORTANCE_NONE) {
Log.d(TAG, "NotificationsEnabled"); Log.d(TAG, "NotificationsEnabled");
return true; return true;
} }
@ -272,13 +276,15 @@ public class NotificationHelper {
} else { } else {
// on Android < O, notifications are enabled, if at least one account has notification enabled // on Android < O, notifications are enabled, if at least one account has notification enabled
return TuskyApplication.getAccountManager().areNotificationsEnabled(); return TuskyApplication.getInstance(context).getServiceLocator()
.get(AccountManager.class).areNotificationsEnabled();
} }
} }
public static void clearNotificationsForActiveAccount(Context context) { public static void clearNotificationsForActiveAccount(Context context) {
AccountManager accountManager = TuskyApplication.getAccountManager(); AccountManager accountManager = TuskyApplication.getInstance(context).getServiceLocator()
.get(AccountManager.class);
AccountEntity account = accountManager.getActiveAccount(); AccountEntity account = accountManager.getActiveAccount();
if (account != null) { if (account != null) {
account.setActiveNotifications("[]"); account.setActiveNotifications("[]");
@ -286,7 +292,7 @@ public class NotificationHelper {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//noinspection ConstantConditions //noinspection ConstantConditions
notificationManager.cancel((int)account.getId()); notificationManager.cancel((int) account.getId());
} }
} }
@ -318,13 +324,13 @@ public class NotificationHelper {
switch (notification.getType()) { switch (notification.getType()) {
default: default:
case MENTION: case MENTION:
return CHANNEL_MENTION+account.getIdentifier(); return CHANNEL_MENTION + account.getIdentifier();
case FOLLOW: case FOLLOW:
return CHANNEL_FOLLOW+account.getIdentifier(); return CHANNEL_FOLLOW + account.getIdentifier();
case REBLOG: case REBLOG:
return CHANNEL_BOOST+account.getIdentifier(); return CHANNEL_BOOST + account.getIdentifier();
case FAVOURITE: case FAVOURITE:
return CHANNEL_FAVOURITE+account.getIdentifier(); return CHANNEL_FAVOURITE + account.getIdentifier();
} }
} }
@ -354,7 +360,7 @@ public class NotificationHelper {
if (array.length() > 3) { if (array.length() > 3) {
int length = array.length(); int length = array.length();
return String.format(context.getString(R.string.notification_summary_large), return String.format(context.getString(R.string.notification_summary_large),
array.get(length-1), array.get(length-2), array.get(length-3), length - 3); array.get(length - 1), array.get(length - 2), array.get(length - 3), length - 3);
} else if (array.length() == 3) { } else if (array.length() == 3) {
return String.format(context.getString(R.string.notification_summary_medium), return String.format(context.getString(R.string.notification_summary_medium),
array.get(2), array.get(1), array.get(0)); array.get(2), array.get(1), array.get(0));
@ -389,7 +395,7 @@ public class NotificationHelper {
private static String bodyForType(Notification notification) { private static String bodyForType(Notification notification) {
switch (notification.getType()) { switch (notification.getType()) {
case FOLLOW: case FOLLOW:
return "@"+ notification.getAccount().getUsername(); return "@" + notification.getAccount().getUsername();
case MENTION: case MENTION:
case FAVOURITE: case FAVOURITE:
case REBLOG: case REBLOG:

View file

@ -0,0 +1,103 @@
package com.keylesspalace.tusky
import android.widget.EditText
import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.db.AccountManager
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import org.robolectric.fakes.RoboMenuItem
/**
* Created by charlag on 3/7/18.
*/
@Config(application = FakeTuskyApplication::class)
@RunWith(RobolectricTestRunner::class)
class ComposeActivityTest {
lateinit var activity: ComposeActivity
lateinit var application: FakeTuskyApplication
lateinit var serviceLocator: TuskyApplication.ServiceLocator
lateinit var accountManagerMock: AccountManager
val account = AccountEntity(
id = 1,
domain = "example.token",
accessToken = "token",
isActive = true,
accountId = "1",
username = "username",
displayName = "Display Name",
profilePictureUrl = "",
notificationsEnabled = true,
notificationsMentioned = true,
notificationsFollowed = true,
notificationsReblogged = true,
notificationsFavorited = true,
notificationSound = true,
notificationVibration = true,
notificationLight = true
)
@Before
fun before() {
val controller = Robolectric.buildActivity(ComposeActivity::class.java)
activity = controller.get()
application = activity.application as FakeTuskyApplication
serviceLocator = Mockito.mock(TuskyApplication.ServiceLocator::class.java)
application.locator = serviceLocator
accountManagerMock = Mockito.mock(AccountManager::class.java)
`when`(serviceLocator.get(AccountManager::class.java)).thenReturn(accountManagerMock)
`when`(accountManagerMock.activeAccount).thenReturn(account)
controller.create().start()
}
@Test
fun whenCloseButtonPressedAndEmpty_finish() {
clickUp()
assertTrue(activity.isFinishing)
}
@Test
fun whenCloseButtonPressedNotEmpty_notFinish() {
insertSomeTextInContent()
clickUp()
assertFalse(activity.isFinishing)
// We would like to check for dialog but Robolectric doesn't work with AppCompat v7 yet
}
@Test
fun whenBackButtonPressedAndEmpty_finish() {
clickBack()
assertTrue(activity.isFinishing)
}
@Test
fun whenBackButtonPressedNotEmpty_notFinish() {
insertSomeTextInContent()
clickBack()
assertFalse(activity.isFinishing)
// We would like to check for dialog but Robolectric doesn't work with AppCompat v7 yet
}
private fun clickUp() {
val menuItem = RoboMenuItem(android.R.id.home)
activity.onOptionsItemSelected(menuItem)
}
private fun clickBack() {
activity.onBackPressed()
}
private fun insertSomeTextInContent() {
activity.findViewById<EditText>(R.id.compose_edit_field).setText("Some text")
}
}

View file

@ -1,17 +0,0 @@
package com.keylesspalace.tusky;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}

View file

@ -0,0 +1,18 @@
package com.keylesspalace.tusky
/**
* Created by charlag on 3/7/18.
*/
class FakeTuskyApplication : TuskyApplication() {
lateinit var locator: ServiceLocator
override fun initPicasso() {
// No-op
}
override fun getServiceLocator(): ServiceLocator {
return locator
}
}