Dependency injection improvement (#596)
* inject MastodonApi into LoginActivity * inject AccountManager into MainActivity * inject AccountManager into SplashActivity, convert to Kotlin * inject AccountManager into AccountActivity * inject AccountManager into LoginActivity * inject AccountManager into NotificationsFragment and NotificationClearBroadcastReceiver, fix MainActivity * ooops * use same OkHttpClient for Retrofit & Picasso * fix ordering of okhttp interceptors * remove dependencies on TuskyApplication * bugfix
This commit is contained in:
parent
d17ff3eb0f
commit
b4ba457d89
18 changed files with 196 additions and 176 deletions
|
@ -88,6 +88,8 @@ public final class AccountActivity extends BaseActivity implements ActionButtonA
|
||||||
@Inject
|
@Inject
|
||||||
public MastodonApi mastodonApi;
|
public MastodonApi mastodonApi;
|
||||||
@Inject
|
@Inject
|
||||||
|
public AccountManager accountManager;
|
||||||
|
@Inject
|
||||||
public DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector;
|
public DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector;
|
||||||
|
|
||||||
private String accountId;
|
private String accountId;
|
||||||
|
@ -207,8 +209,7 @@ 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.getInstance(this).getServiceLocator()
|
AccountEntity activeAccount = accountManager.getActiveAccount();
|
||||||
.get(AccountManager.class).getActiveAccount();
|
|
||||||
|
|
||||||
if (accountId.equals(activeAccount.getAccountId())) {
|
if (accountId.equals(activeAccount.getAccountId())) {
|
||||||
isSelf = true;
|
isSelf = true;
|
||||||
|
|
|
@ -45,8 +45,8 @@ public abstract class BaseActivity extends AppCompatActivity {
|
||||||
/* 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
|
||||||
* runtime, just individual activities. So, each activity has to set its theme before any
|
* runtime, just individual activities. So, each activity has to set its theme before any
|
||||||
* views are created. */
|
* views are created. */
|
||||||
String theme = preferences.getString("appTheme", TuskyApplication.APP_THEME_DEFAULT);
|
String theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT);
|
||||||
ThemeUtils.setAppNightMode(theme);
|
ThemeUtils.setAppNightMode(theme, this);
|
||||||
|
|
||||||
int style;
|
int style;
|
||||||
switch (preferences.getString("statusTextSize", "medium")) {
|
switch (preferences.getString("statusTextSize", "medium")) {
|
||||||
|
|
|
@ -32,21 +32,26 @@ 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.db.AccountManager
|
||||||
|
import com.keylesspalace.tusky.di.Injectable
|
||||||
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
|
||||||
import com.keylesspalace.tusky.util.CustomTabsHelper
|
import com.keylesspalace.tusky.util.CustomTabsHelper
|
||||||
import com.keylesspalace.tusky.util.OkHttpUtils
|
|
||||||
import com.keylesspalace.tusky.util.ThemeUtils
|
import com.keylesspalace.tusky.util.ThemeUtils
|
||||||
import kotlinx.android.synthetic.main.activity_login.*
|
import kotlinx.android.synthetic.main.activity_login.*
|
||||||
|
import okhttp3.HttpUrl
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import retrofit2.Retrofit
|
import javax.inject.Inject
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
|
||||||
|
|
||||||
|
|
||||||
class LoginActivity : AppCompatActivity() {
|
class LoginActivity : AppCompatActivity(), Injectable {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var mastodonApi: MastodonApi
|
||||||
|
@Inject
|
||||||
|
lateinit var accountManager: AccountManager
|
||||||
|
|
||||||
private lateinit var preferences: SharedPreferences
|
private lateinit var preferences: SharedPreferences
|
||||||
private var domain: String = ""
|
private var domain: String = ""
|
||||||
|
@ -64,8 +69,8 @@ class LoginActivity : AppCompatActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
val theme = preferences.getString("appTheme", TuskyApplication.APP_THEME_DEFAULT)
|
val theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT)
|
||||||
ThemeUtils.setAppNightMode(theme)
|
ThemeUtils.setAppNightMode(theme, this)
|
||||||
|
|
||||||
setContentView(R.layout.activity_login)
|
setContentView(R.layout.activity_login)
|
||||||
|
|
||||||
|
@ -114,16 +119,6 @@ class LoginActivity : AppCompatActivity() {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getApiFor(domain: String): MastodonApi {
|
|
||||||
val retrofit = Retrofit.Builder()
|
|
||||||
.baseUrl("https://" + domain)
|
|
||||||
.client(OkHttpUtils.getCompatibleClient(preferences))
|
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
|
||||||
.build()
|
|
||||||
|
|
||||||
return retrofit.create(MastodonApi::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the oauth client credentials for this app. This is only necessary the first time the
|
* Obtain the oauth client credentials for this app. This is only necessary the first time the
|
||||||
* app is run on a given server instance. So, after the first authentication, they are
|
* app is run on a given server instance. So, after the first authentication, they are
|
||||||
|
@ -133,7 +128,15 @@ class LoginActivity : AppCompatActivity() {
|
||||||
|
|
||||||
loginButton.isEnabled = false
|
loginButton.isEnabled = false
|
||||||
|
|
||||||
domain = validateDomain(domainEditText.text.toString())
|
domain = canonicalizeDomain(domainEditText.text.toString())
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpUrl.Builder().host(domain).scheme("https").build()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
setLoading(false)
|
||||||
|
domainEditText.error = getString(R.string.error_invalid_domain)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val callback = object : Callback<AppCredentials> {
|
val callback = object : Callback<AppCredentials> {
|
||||||
override fun onResponse(call: Call<AppCredentials>,
|
override fun onResponse(call: Call<AppCredentials>,
|
||||||
|
@ -159,16 +162,11 @@ class LoginActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
mastodonApi
|
||||||
getApiFor(domain)
|
.authenticateApp(domain, getString(R.string.app_name), oauthRedirectUri,
|
||||||
.authenticateApp(getString(R.string.app_name), oauthRedirectUri,
|
|
||||||
OAUTH_SCOPES, getString(R.string.app_website))
|
OAUTH_SCOPES, getString(R.string.app_website))
|
||||||
.enqueue(callback)
|
.enqueue(callback)
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
setLoading(false)
|
|
||||||
domainEditText.error = getString(R.string.error_invalid_domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +248,7 @@ class LoginActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getApiFor(domain).fetchOAuthToken(clientId, clientSecret, redirectUri, code,
|
mastodonApi.fetchOAuthToken(domain, clientId, clientSecret, redirectUri, code,
|
||||||
"authorization_code").enqueue(callback)
|
"authorization_code").enqueue(callback)
|
||||||
} else if (error != null) {
|
} else if (error != null) {
|
||||||
/* Authorization failed. Put the error response where the user can read it and they
|
/* Authorization failed. Put the error response where the user can read it and they
|
||||||
|
@ -290,9 +288,7 @@ class LoginActivity : AppCompatActivity() {
|
||||||
|
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|
||||||
TuskyApplication.getInstance(this).serviceLocator
|
accountManager.addAccount(accessToken, domain)
|
||||||
.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
|
||||||
|
@ -316,14 +312,10 @@ class LoginActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make sure the user-entered text is just a fully-qualified domain name. */
|
/** Make sure the user-entered text is just a fully-qualified domain name. */
|
||||||
private fun validateDomain(domain: String): String {
|
private fun canonicalizeDomain(domain: String): String {
|
||||||
// Strip any schemes out.
|
// Strip any schemes out.
|
||||||
var s = domain.replaceFirst("http://", "")
|
var s = domain.replaceFirst("http://", "")
|
||||||
s = s.replaceFirst("https://", "")
|
s = s.replaceFirst("https://", "")
|
||||||
|
|
||||||
//strip out any slashes that might have been added
|
|
||||||
s = s.replace("/", "")
|
|
||||||
|
|
||||||
// If a username was included (e.g. username@example.com), just take what's after the '@'.
|
// If a username was included (e.g. username@example.com), just take what's after the '@'.
|
||||||
val at = s.lastIndexOf('@')
|
val at = s.lastIndexOf('@')
|
||||||
if (at != -1) {
|
if (at != -1) {
|
||||||
|
|
|
@ -92,11 +92,11 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity,
|
||||||
public MastodonApi mastodonApi;
|
public MastodonApi mastodonApi;
|
||||||
@Inject
|
@Inject
|
||||||
public DispatchingAndroidInjector<Fragment> fragmentInjector;
|
public DispatchingAndroidInjector<Fragment> fragmentInjector;
|
||||||
|
@Inject
|
||||||
|
public AccountManager accountManager;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -107,9 +107,6 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity,
|
||||||
Intent intent = getIntent();
|
Intent intent = getIntent();
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -104,8 +104,8 @@ public class PreferencesActivity extends BaseActivity
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "appTheme": {
|
case "appTheme": {
|
||||||
String theme = sharedPreferences.getString("appTheme", TuskyApplication.APP_THEME_DEFAULT);
|
String theme = sharedPreferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT);
|
||||||
ThemeUtils.setAppNightMode(theme);
|
ThemeUtils.setAppNightMode(theme, this);
|
||||||
restartActivitiesOnExit = true;
|
restartActivitiesOnExit = true;
|
||||||
|
|
||||||
// recreate() could be used instead, but it doesn't have an animation B).
|
// recreate() could be used instead, but it doesn't have an animation B).
|
||||||
|
|
|
@ -1,48 +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.os.Bundle;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
|
|
||||||
import com.keylesspalace.tusky.db.AccountEntity;
|
|
||||||
import com.keylesspalace.tusky.db.AccountManager;
|
|
||||||
import com.keylesspalace.tusky.util.NotificationHelper;
|
|
||||||
|
|
||||||
public class SplashActivity extends AppCompatActivity {
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
|
|
||||||
/* Determine whether the user is currently logged in, and if so go ahead and load the
|
|
||||||
* timeline. Otherwise, start the activity_login screen. */
|
|
||||||
|
|
||||||
NotificationHelper.deleteLegacyNotificationChannels(this);
|
|
||||||
|
|
||||||
AccountEntity activeAccount = TuskyApplication.getInstance(this).getServiceLocator()
|
|
||||||
.get(AccountManager.class).getActiveAccount();
|
|
||||||
|
|
||||||
Intent intent;
|
|
||||||
if (activeAccount != null) {
|
|
||||||
intent = new Intent(this, MainActivity.class);
|
|
||||||
} else {
|
|
||||||
intent = LoginActivity.getIntent(this, false);
|
|
||||||
}
|
|
||||||
startActivity(intent);
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
50
app/src/main/java/com/keylesspalace/tusky/SplashActivity.kt
Normal file
50
app/src/main/java/com/keylesspalace/tusky/SplashActivity.kt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/* 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.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
|
||||||
|
import com.keylesspalace.tusky.db.AccountManager
|
||||||
|
import com.keylesspalace.tusky.di.Injectable
|
||||||
|
import com.keylesspalace.tusky.util.NotificationHelper
|
||||||
|
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SplashActivity : AppCompatActivity(), Injectable {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var accountManager: AccountManager
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
/** delete old notification channels that were in use in Tusky 1.4 */
|
||||||
|
NotificationHelper.deleteLegacyNotificationChannels(this)
|
||||||
|
|
||||||
|
/** Determine whether the user is currently logged in, and if so go ahead and load the
|
||||||
|
* timeline. Otherwise, start the activity_login screen. */
|
||||||
|
|
||||||
|
val intent = if (accountManager.activeAccount != null) {
|
||||||
|
Intent(this, MainActivity::class.java)
|
||||||
|
} else {
|
||||||
|
LoginActivity.getIntent(this, false)
|
||||||
|
}
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,11 +18,9 @@ package com.keylesspalace.tusky;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.app.UiModeManager;
|
|
||||||
import android.arch.persistence.room.Room;
|
import android.arch.persistence.room.Room;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v7.app.AppCompatDelegate;
|
import android.support.v7.app.AppCompatDelegate;
|
||||||
|
|
||||||
|
@ -31,8 +29,6 @@ import com.jakewharton.picasso.OkHttp3Downloader;
|
||||||
import com.keylesspalace.tusky.db.AccountManager;
|
import com.keylesspalace.tusky.db.AccountManager;
|
||||||
import com.keylesspalace.tusky.db.AppDatabase;
|
import com.keylesspalace.tusky.db.AppDatabase;
|
||||||
import com.keylesspalace.tusky.di.AppInjector;
|
import com.keylesspalace.tusky.di.AppInjector;
|
||||||
import com.keylesspalace.tusky.util.OkHttpUtils;
|
|
||||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
|
||||||
import com.squareup.picasso.Picasso;
|
import com.squareup.picasso.Picasso;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -40,13 +36,11 @@ import javax.inject.Inject;
|
||||||
import dagger.android.AndroidInjector;
|
import dagger.android.AndroidInjector;
|
||||||
import dagger.android.DispatchingAndroidInjector;
|
import dagger.android.DispatchingAndroidInjector;
|
||||||
import dagger.android.HasActivityInjector;
|
import dagger.android.HasActivityInjector;
|
||||||
|
import dagger.android.HasBroadcastReceiverInjector;
|
||||||
import dagger.android.HasServiceInjector;
|
import dagger.android.HasServiceInjector;
|
||||||
import okhttp3.Cache;
|
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
|
||||||
public class TuskyApplication extends Application implements HasActivityInjector, HasServiceInjector {
|
public class TuskyApplication extends Application implements HasActivityInjector, HasServiceInjector, HasBroadcastReceiverInjector {
|
||||||
public static final String APP_THEME_DEFAULT = ThemeUtils.THEME_NIGHT;
|
|
||||||
|
|
||||||
private static AppDatabase db;
|
private static AppDatabase db;
|
||||||
private AccountManager accountManager;
|
private AccountManager accountManager;
|
||||||
@Inject
|
@Inject
|
||||||
|
@ -54,23 +48,19 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
||||||
@Inject
|
@Inject
|
||||||
DispatchingAndroidInjector<Service> dispatchingServiceInjector;
|
DispatchingAndroidInjector<Service> dispatchingServiceInjector;
|
||||||
@Inject
|
@Inject
|
||||||
|
DispatchingAndroidInjector<BroadcastReceiver> dispatchingBroadcastReceiverInjector;
|
||||||
|
@Inject
|
||||||
NotificationPullJobCreator notificationPullJobCreator;
|
NotificationPullJobCreator notificationPullJobCreator;
|
||||||
|
@Inject OkHttpClient okHttpClient;
|
||||||
|
|
||||||
public static AppDatabase getDB() {
|
public static AppDatabase getDB() {
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UiModeManager uiModeManager;
|
|
||||||
|
|
||||||
public static UiModeManager getUiModeManager() {
|
|
||||||
return uiModeManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TuskyApplication getInstance(@NonNull Context context) {
|
public static TuskyApplication getInstance(@NonNull Context context) {
|
||||||
return (TuskyApplication) context.getApplicationContext();
|
return (TuskyApplication) context.getApplicationContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ServiceLocator serviceLocator;
|
private ServiceLocator serviceLocator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -98,7 +88,6 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
||||||
initPicasso();
|
initPicasso();
|
||||||
|
|
||||||
JobManager.create(this).addJobCreator(notificationPullJobCreator);
|
JobManager.create(this).addJobCreator(notificationPullJobCreator);
|
||||||
uiModeManager = (UiModeManager) getSystemService(Context.UI_MODE_SERVICE);
|
|
||||||
|
|
||||||
//necessary for Android < APi 21
|
//necessary for Android < APi 21
|
||||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||||
|
@ -111,15 +100,7 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
||||||
protected void initPicasso() {
|
protected void initPicasso() {
|
||||||
// Initialize Picasso configuration
|
// Initialize Picasso configuration
|
||||||
Picasso.Builder builder = new Picasso.Builder(this);
|
Picasso.Builder builder = new Picasso.Builder(this);
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
builder.downloader(new OkHttp3Downloader(okHttpClient));
|
||||||
|
|
||||||
OkHttpClient.Builder okHttpBuilder = OkHttpUtils.getCompatibleClientBuilder(preferences);
|
|
||||||
|
|
||||||
int cacheSize = 10*1024*1024; // 10 MiB
|
|
||||||
|
|
||||||
okHttpBuilder.cache(new Cache(getCacheDir(), cacheSize));
|
|
||||||
|
|
||||||
builder.downloader(new OkHttp3Downloader(okHttpBuilder.build()));
|
|
||||||
if (BuildConfig.DEBUG) {
|
if (BuildConfig.DEBUG) {
|
||||||
builder.listener((picasso, uri, exception) -> exception.printStackTrace());
|
builder.listener((picasso, uri, exception) -> exception.printStackTrace());
|
||||||
}
|
}
|
||||||
|
@ -141,6 +122,11 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
||||||
return dispatchingServiceInjector;
|
return dispatchingServiceInjector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AndroidInjector<BroadcastReceiver> broadcastReceiverInjector() {
|
||||||
|
return dispatchingBroadcastReceiverInjector;
|
||||||
|
}
|
||||||
|
|
||||||
public interface ServiceLocator {
|
public interface ServiceLocator {
|
||||||
<T> T get(Class<T> clazz);
|
<T> T get(Class<T> clazz);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,13 @@ abstract class ActivitiesModule {
|
||||||
@ContributesAndroidInjector()
|
@ContributesAndroidInjector()
|
||||||
abstract fun contributesAboutActivity(): AboutActivity
|
abstract fun contributesAboutActivity(): AboutActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector()
|
||||||
|
abstract fun contributesLoginActivity(): LoginActivity
|
||||||
|
|
||||||
|
@ContributesAndroidInjector()
|
||||||
|
abstract fun contributesSplashActivity(): SplashActivity
|
||||||
|
|
||||||
@ContributesAndroidInjector
|
@ContributesAndroidInjector
|
||||||
abstract fun contributesReportActivity(): ReportActivity
|
abstract fun contributesReportActivity(): ReportActivity
|
||||||
|
|
||||||
}
|
}
|
|
@ -32,7 +32,8 @@ import javax.inject.Singleton
|
||||||
NetworkModule::class,
|
NetworkModule::class,
|
||||||
AndroidInjectionModule::class,
|
AndroidInjectionModule::class,
|
||||||
ActivitiesModule::class,
|
ActivitiesModule::class,
|
||||||
ServicesModule::class
|
ServicesModule::class,
|
||||||
|
BroadcastReceiverModule::class
|
||||||
])
|
])
|
||||||
interface AppComponent {
|
interface AppComponent {
|
||||||
@Component.Builder
|
@Component.Builder
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* 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.di
|
||||||
|
|
||||||
|
import com.keylesspalace.tusky.receiver.NotificationClearBroadcastReceiver
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.android.ContributesAndroidInjector
|
||||||
|
|
||||||
|
@Module
|
||||||
|
abstract class BroadcastReceiverModule {
|
||||||
|
@ContributesAndroidInjector
|
||||||
|
abstract fun contributeNotificationClearBroadcastReceiver() : NotificationClearBroadcastReceiver
|
||||||
|
}
|
|
@ -16,11 +16,12 @@
|
||||||
|
|
||||||
package com.keylesspalace.tusky.di
|
package com.keylesspalace.tusky.di
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.Context
|
||||||
import android.text.Spanned
|
import android.text.Spanned
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import com.google.gson.JsonDeserializer
|
import com.google.gson.JsonDeserializer
|
||||||
|
import com.keylesspalace.tusky.BuildConfig
|
||||||
import com.keylesspalace.tusky.db.AccountManager
|
import com.keylesspalace.tusky.db.AccountManager
|
||||||
import com.keylesspalace.tusky.json.SpannedTypeAdapter
|
import com.keylesspalace.tusky.json.SpannedTypeAdapter
|
||||||
import com.keylesspalace.tusky.network.InstanceSwitchAuthInterceptor
|
import com.keylesspalace.tusky.network.InstanceSwitchAuthInterceptor
|
||||||
|
@ -31,8 +32,8 @@ import dagger.Provides
|
||||||
import dagger.multibindings.ClassKey
|
import dagger.multibindings.ClassKey
|
||||||
import dagger.multibindings.IntoMap
|
import dagger.multibindings.IntoMap
|
||||||
import dagger.multibindings.IntoSet
|
import dagger.multibindings.IntoSet
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
import retrofit2.Converter
|
import retrofit2.Converter
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.gson.GsonConverterFactory
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
@ -67,32 +68,24 @@ class NetworkModule {
|
||||||
fun providesConverterFactory(gson: Gson): Converter.Factory = GsonConverterFactory.create(gson)
|
fun providesConverterFactory(gson: Gson): Converter.Factory = GsonConverterFactory.create(gson)
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@IntoSet
|
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providesAuthInterceptor(accountManager: AccountManager): Interceptor {
|
fun providesHttpClient(accountManager: AccountManager,
|
||||||
// should accept AccountManager here probably but I don't want to break things yet
|
context: Context): OkHttpClient {
|
||||||
return InstanceSwitchAuthInterceptor(accountManager)
|
return OkHttpUtils.getCompatibleClientBuilder(context)
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun providesHttpClient(interceptors: @JvmSuppressWildcards Set<Interceptor>,
|
|
||||||
preferences: SharedPreferences): OkHttpClient {
|
|
||||||
return OkHttpUtils.getCompatibleClientBuilder(preferences)
|
|
||||||
.apply {
|
.apply {
|
||||||
interceptors.fold(this) { b, i ->
|
addInterceptor(InstanceSwitchAuthInterceptor(accountManager))
|
||||||
b.addInterceptor(i)
|
if (BuildConfig.DEBUG) {
|
||||||
|
addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun providesRetrofit(httpClient: OkHttpClient,
|
fun providesRetrofit(httpClient: OkHttpClient,
|
||||||
converters: @JvmSuppressWildcards Set<Converter.Factory>): Retrofit {
|
converters: @JvmSuppressWildcards Set<Converter.Factory>): Retrofit {
|
||||||
return Retrofit.Builder().baseUrl("https://dummy.placeholder/")
|
return Retrofit.Builder().baseUrl("https://"+MastodonApi.PLACEHOLDER_DOMAIN)
|
||||||
.client(httpClient)
|
.client(httpClient)
|
||||||
.let { builder ->
|
.let { builder ->
|
||||||
// Doing it this way in case builder will be immutable so we return the final
|
// Doing it this way in case builder will be immutable so we return the final
|
||||||
|
|
|
@ -38,7 +38,6 @@ import android.view.ViewGroup;
|
||||||
|
|
||||||
import com.keylesspalace.tusky.MainActivity;
|
import com.keylesspalace.tusky.MainActivity;
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.TuskyApplication;
|
|
||||||
import com.keylesspalace.tusky.adapter.FooterViewHolder;
|
import com.keylesspalace.tusky.adapter.FooterViewHolder;
|
||||||
import com.keylesspalace.tusky.adapter.NotificationsAdapter;
|
import com.keylesspalace.tusky.adapter.NotificationsAdapter;
|
||||||
import com.keylesspalace.tusky.db.AccountEntity;
|
import com.keylesspalace.tusky.db.AccountEntity;
|
||||||
|
@ -108,6 +107,8 @@ public class NotificationsFragment extends SFragment implements
|
||||||
public TimelineCases timelineCases;
|
public TimelineCases timelineCases;
|
||||||
@Inject
|
@Inject
|
||||||
public MastodonApi mastodonApi;
|
public MastodonApi mastodonApi;
|
||||||
|
@Inject
|
||||||
|
AccountManager accountManager;
|
||||||
|
|
||||||
private SwipeRefreshLayout swipeRefreshLayout;
|
private SwipeRefreshLayout swipeRefreshLayout;
|
||||||
private LinearLayoutManager layoutManager;
|
private LinearLayoutManager layoutManager;
|
||||||
|
@ -606,8 +607,7 @@ public class NotificationsFragment extends SFragment implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveNewestNotificationId(List<Notification> notifications) {
|
private void saveNewestNotificationId(List<Notification> notifications) {
|
||||||
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());
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,9 @@ public final class InstanceSwitchAuthInterceptor implements Interceptor {
|
||||||
public Response intercept(@NonNull Chain chain) throws IOException {
|
public Response intercept(@NonNull Chain chain) throws IOException {
|
||||||
|
|
||||||
Request originalRequest = chain.request();
|
Request originalRequest = chain.request();
|
||||||
|
|
||||||
|
// only switch domains if the request comes from retrofit
|
||||||
|
if (originalRequest.url().host().equals(MastodonApi.PLACEHOLDER_DOMAIN)) {
|
||||||
AccountEntity currentAccount = accountManager.getActiveAccount();
|
AccountEntity currentAccount = accountManager.getActiveAccount();
|
||||||
|
|
||||||
Request.Builder builder = originalRequest.newBuilder();
|
Request.Builder builder = originalRequest.newBuilder();
|
||||||
|
@ -60,10 +63,14 @@ public final class InstanceSwitchAuthInterceptor implements Interceptor {
|
||||||
Request newRequest = builder.build();
|
Request newRequest = builder.build();
|
||||||
|
|
||||||
return chain.proceed(newRequest);
|
return chain.proceed(newRequest);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return chain.proceed(originalRequest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private HttpUrl swapHost(@NonNull HttpUrl url, @NonNull String host) {
|
private static HttpUrl swapHost(@NonNull HttpUrl url, @NonNull String host) {
|
||||||
return url.newBuilder().host(host).build();
|
return url.newBuilder().host(host).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ import retrofit2.http.Query;
|
||||||
public interface MastodonApi {
|
public interface MastodonApi {
|
||||||
String ENDPOINT_AUTHORIZE = "/oauth/authorize";
|
String ENDPOINT_AUTHORIZE = "/oauth/authorize";
|
||||||
String DOMAIN_HEADER = "domain";
|
String DOMAIN_HEADER = "domain";
|
||||||
|
String PLACEHOLDER_DOMAIN = "dummy.placeholder";
|
||||||
|
|
||||||
@GET("api/v1/timelines/home")
|
@GET("api/v1/timelines/home")
|
||||||
Call<List<Status>> homeTimeline(
|
Call<List<Status>> homeTimeline(
|
||||||
|
@ -246,6 +247,7 @@ public interface MastodonApi {
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("api/v1/apps")
|
@POST("api/v1/apps")
|
||||||
Call<AppCredentials> authenticateApp(
|
Call<AppCredentials> authenticateApp(
|
||||||
|
@Header(DOMAIN_HEADER) String domain,
|
||||||
@Field("client_name") String clientName,
|
@Field("client_name") String clientName,
|
||||||
@Field("redirect_uris") String redirectUris,
|
@Field("redirect_uris") String redirectUris,
|
||||||
@Field("scopes") String scopes,
|
@Field("scopes") String scopes,
|
||||||
|
@ -254,6 +256,7 @@ public interface MastodonApi {
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@POST("oauth/token")
|
@POST("oauth/token")
|
||||||
Call<AccessToken> fetchOAuthToken(
|
Call<AccessToken> fetchOAuthToken(
|
||||||
|
@Header(DOMAIN_HEADER) String domain,
|
||||||
@Field("client_id") String clientId,
|
@Field("client_id") String clientId,
|
||||||
@Field("client_secret") String clientSecret,
|
@Field("client_secret") String clientSecret,
|
||||||
@Field("redirect_uri") String redirectUri,
|
@Field("redirect_uri") String redirectUri,
|
||||||
|
|
|
@ -19,17 +19,21 @@ import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
|
||||||
import com.keylesspalace.tusky.TuskyApplication
|
|
||||||
import com.keylesspalace.tusky.db.AccountManager
|
import com.keylesspalace.tusky.db.AccountManager
|
||||||
import com.keylesspalace.tusky.util.NotificationHelper
|
import com.keylesspalace.tusky.util.NotificationHelper
|
||||||
|
import dagger.android.AndroidInjection
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class NotificationClearBroadcastReceiver : BroadcastReceiver() {
|
class NotificationClearBroadcastReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var accountManager: AccountManager
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
AndroidInjection.inject(this, context)
|
||||||
|
|
||||||
val accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1)
|
val accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1)
|
||||||
|
|
||||||
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 = "[]"
|
||||||
|
|
|
@ -15,8 +15,10 @@
|
||||||
|
|
||||||
package com.keylesspalace.tusky.util;
|
package com.keylesspalace.tusky.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
@ -43,11 +45,11 @@ import javax.net.ssl.TrustManager;
|
||||||
import javax.net.ssl.TrustManagerFactory;
|
import javax.net.ssl.TrustManagerFactory;
|
||||||
import javax.net.ssl.X509TrustManager;
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
import okhttp3.Cache;
|
||||||
import okhttp3.ConnectionSpec;
|
import okhttp3.ConnectionSpec;
|
||||||
import okhttp3.Interceptor;
|
import okhttp3.Interceptor;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
|
||||||
|
|
||||||
public class OkHttpUtils {
|
public class OkHttpUtils {
|
||||||
private static final String TAG = "OkHttpUtils"; // logging tag
|
private static final String TAG = "OkHttpUtils"; // logging tag
|
||||||
|
@ -65,7 +67,11 @@ public class OkHttpUtils {
|
||||||
* TLS 1.1 and 1.2 have to be manually enabled on API levels 16-20.
|
* TLS 1.1 and 1.2 have to be manually enabled on API levels 16-20.
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static OkHttpClient.Builder getCompatibleClientBuilder(SharedPreferences preferences) {
|
public static OkHttpClient.Builder getCompatibleClientBuilder(@NonNull Context context) {
|
||||||
|
|
||||||
|
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
|
||||||
|
|
||||||
boolean httpProxyEnabled = preferences.getBoolean("httpProxyEnabled", false);
|
boolean httpProxyEnabled = preferences.getBoolean("httpProxyEnabled", false);
|
||||||
String httpServer = preferences.getString("httpProxyServer", "");
|
String httpServer = preferences.getString("httpProxyServer", "");
|
||||||
int httpPort = Integer.parseInt(preferences.getString("httpProxyPort", "-1"));
|
int httpPort = Integer.parseInt(preferences.getString("httpProxyPort", "-1"));
|
||||||
|
@ -81,10 +87,13 @@ public class OkHttpUtils {
|
||||||
specList.add(fallback);
|
specList.add(fallback);
|
||||||
specList.add(ConnectionSpec.CLEARTEXT);
|
specList.add(ConnectionSpec.CLEARTEXT);
|
||||||
|
|
||||||
|
int cacheSize = 10*1024*1024; // 10 MiB
|
||||||
|
|
||||||
OkHttpClient.Builder builder = new OkHttpClient.Builder()
|
OkHttpClient.Builder builder = new OkHttpClient.Builder()
|
||||||
.addInterceptor(getUserAgentInterceptor())
|
.addInterceptor(getUserAgentInterceptor())
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
.writeTimeout(30, TimeUnit.SECONDS)
|
.writeTimeout(30, TimeUnit.SECONDS)
|
||||||
|
.cache(new Cache(context.getCacheDir(), cacheSize))
|
||||||
.connectionSpecs(specList);
|
.connectionSpecs(specList);
|
||||||
|
|
||||||
if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0) && (httpPort < 65535)) {
|
if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0) && (httpPort < 65535)) {
|
||||||
|
@ -92,18 +101,9 @@ public class OkHttpUtils {
|
||||||
builder.proxy(new Proxy(Proxy.Type.HTTP, address));
|
builder.proxy(new Proxy(Proxy.Type.HTTP, address));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(BuildConfig.DEBUG) {
|
|
||||||
builder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC));
|
|
||||||
}
|
|
||||||
|
|
||||||
return enableHigherTlsOnPreLollipop(builder);
|
return enableHigherTlsOnPreLollipop(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static OkHttpClient getCompatibleClient(SharedPreferences preferences) {
|
|
||||||
return getCompatibleClientBuilder(preferences).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a custom User-Agent that contains Tusky & Android Version to all requests
|
* Add a custom User-Agent that contains Tusky & Android Version to all requests
|
||||||
* Example:
|
* Example:
|
||||||
|
|
|
@ -30,13 +30,13 @@ import android.support.v7.app.AppCompatDelegate;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import com.keylesspalace.tusky.TuskyApplication;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides runtime compatibility to obtain theme information and re-theme views, especially where
|
* Provides runtime compatibility to obtain theme information and re-theme views, especially where
|
||||||
* the ability to do so is not supported in resource files.
|
* the ability to do so is not supported in resource files.
|
||||||
*/
|
*/
|
||||||
public class ThemeUtils {
|
public class ThemeUtils {
|
||||||
|
public static final String APP_THEME_DEFAULT = ThemeUtils.THEME_NIGHT;
|
||||||
|
|
||||||
public static final String THEME_NIGHT = "night";
|
public static final String THEME_NIGHT = "night";
|
||||||
public static final String THEME_DAY = "day";
|
public static final String THEME_DAY = "day";
|
||||||
public static final String THEME_AUTO = "auto";
|
public static final String THEME_AUTO = "auto";
|
||||||
|
@ -91,7 +91,7 @@ public class ThemeUtils {
|
||||||
drawable.setColorFilter(getColor(context, attribute), PorterDuff.Mode.SRC_IN);
|
drawable.setColorFilter(getColor(context, attribute), PorterDuff.Mode.SRC_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setAppNightMode(String flavor) {
|
public static void setAppNightMode(String flavor, Context context) {
|
||||||
int mode;
|
int mode;
|
||||||
switch (flavor) {
|
switch (flavor) {
|
||||||
default:
|
default:
|
||||||
|
@ -107,7 +107,8 @@ public class ThemeUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
TuskyApplication.getUiModeManager().setNightMode(mode);
|
UiModeManager uiModeManager = (UiModeManager)context.getApplicationContext().getSystemService(Context.UI_MODE_SERVICE);
|
||||||
|
uiModeManager.setNightMode(mode);
|
||||||
} else {
|
} else {
|
||||||
AppCompatDelegate.setDefaultNightMode(mode);
|
AppCompatDelegate.setDefaultNightMode(mode);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue