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
|
||||
public MastodonApi mastodonApi;
|
||||
@Inject
|
||||
public AccountManager accountManager;
|
||||
@Inject
|
||||
public DispatchingAndroidInjector<Fragment> dispatchingAndroidInjector;
|
||||
|
||||
private String accountId;
|
||||
|
@ -207,8 +209,7 @@ public final class AccountActivity extends BaseActivity implements ActionButtonA
|
|||
// Obtain information to fill out the profile.
|
||||
obtainAccount();
|
||||
|
||||
AccountEntity activeAccount = TuskyApplication.getInstance(this).getServiceLocator()
|
||||
.get(AccountManager.class).getActiveAccount();
|
||||
AccountEntity activeAccount = accountManager.getActiveAccount();
|
||||
|
||||
if (accountId.equals(activeAccount.getAccountId())) {
|
||||
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
|
||||
* runtime, just individual activities. So, each activity has to set its theme before any
|
||||
* views are created. */
|
||||
String theme = preferences.getString("appTheme", TuskyApplication.APP_THEME_DEFAULT);
|
||||
ThemeUtils.setAppNightMode(theme);
|
||||
String theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT);
|
||||
ThemeUtils.setAppNightMode(theme, this);
|
||||
|
||||
int style;
|
||||
switch (preferences.getString("statusTextSize", "medium")) {
|
||||
|
|
|
@ -32,21 +32,26 @@ import android.view.View
|
|||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.entity.AccessToken
|
||||
import com.keylesspalace.tusky.entity.AppCredentials
|
||||
import com.keylesspalace.tusky.network.MastodonApi
|
||||
import com.keylesspalace.tusky.util.CustomTabsHelper
|
||||
import com.keylesspalace.tusky.util.OkHttpUtils
|
||||
import com.keylesspalace.tusky.util.ThemeUtils
|
||||
import kotlinx.android.synthetic.main.activity_login.*
|
||||
import okhttp3.HttpUrl
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
class LoginActivity : AppCompatActivity() {
|
||||
class LoginActivity : AppCompatActivity(), Injectable {
|
||||
|
||||
@Inject
|
||||
lateinit var mastodonApi: MastodonApi
|
||||
@Inject
|
||||
lateinit var accountManager: AccountManager
|
||||
|
||||
private lateinit var preferences: SharedPreferences
|
||||
private var domain: String = ""
|
||||
|
@ -64,8 +69,8 @@ class LoginActivity : AppCompatActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
val theme = preferences.getString("appTheme", TuskyApplication.APP_THEME_DEFAULT)
|
||||
ThemeUtils.setAppNightMode(theme)
|
||||
val theme = preferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT)
|
||||
ThemeUtils.setAppNightMode(theme, this)
|
||||
|
||||
setContentView(R.layout.activity_login)
|
||||
|
||||
|
@ -114,16 +119,6 @@ class LoginActivity : AppCompatActivity() {
|
|||
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
|
||||
* 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
|
||||
|
||||
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> {
|
||||
override fun onResponse(call: Call<AppCredentials>,
|
||||
|
@ -159,16 +162,11 @@ class LoginActivity : AppCompatActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
try {
|
||||
getApiFor(domain)
|
||||
.authenticateApp(getString(R.string.app_name), oauthRedirectUri,
|
||||
mastodonApi
|
||||
.authenticateApp(domain, getString(R.string.app_name), oauthRedirectUri,
|
||||
OAUTH_SCOPES, getString(R.string.app_website))
|
||||
.enqueue(callback)
|
||||
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)
|
||||
} else if (error != null) {
|
||||
/* Authorization failed. Put the error response where the user can read it and they
|
||||
|
@ -290,9 +288,7 @@ class LoginActivity : AppCompatActivity() {
|
|||
|
||||
setLoading(true)
|
||||
|
||||
TuskyApplication.getInstance(this).serviceLocator
|
||||
.get(AccountManager::class.java)
|
||||
.addAccount(accessToken, domain)
|
||||
accountManager.addAccount(accessToken, domain)
|
||||
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
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. */
|
||||
private fun validateDomain(domain: String): String {
|
||||
private fun canonicalizeDomain(domain: String): String {
|
||||
// Strip any schemes out.
|
||||
var s = domain.replaceFirst("http://", "")
|
||||
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 '@'.
|
||||
val at = s.lastIndexOf('@')
|
||||
if (at != -1) {
|
||||
|
|
|
@ -92,11 +92,11 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity,
|
|||
public MastodonApi mastodonApi;
|
||||
@Inject
|
||||
public DispatchingAndroidInjector<Fragment> fragmentInjector;
|
||||
@Inject
|
||||
public AccountManager accountManager;
|
||||
|
||||
private static int COMPOSE_RESULT = 1;
|
||||
|
||||
AccountManager accountManager;
|
||||
|
||||
private FloatingActionButton composeButton;
|
||||
private AccountHeader headerResult;
|
||||
private Drawer drawer;
|
||||
|
@ -107,9 +107,6 @@ public class MainActivity extends BaseActivity implements ActionButtonActivity,
|
|||
Intent intent = getIntent();
|
||||
int tabPosition = 0;
|
||||
|
||||
accountManager = TuskyApplication.getInstance(this).getServiceLocator()
|
||||
.get(AccountManager.class);
|
||||
|
||||
if (intent != null) {
|
||||
long accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1);
|
||||
|
||||
|
|
|
@ -104,8 +104,8 @@ public class PreferencesActivity extends BaseActivity
|
|||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
switch (key) {
|
||||
case "appTheme": {
|
||||
String theme = sharedPreferences.getString("appTheme", TuskyApplication.APP_THEME_DEFAULT);
|
||||
ThemeUtils.setAppNightMode(theme);
|
||||
String theme = sharedPreferences.getString("appTheme", ThemeUtils.APP_THEME_DEFAULT);
|
||||
ThemeUtils.setAppNightMode(theme, this);
|
||||
restartActivitiesOnExit = true;
|
||||
|
||||
// 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.Application;
|
||||
import android.app.Service;
|
||||
import android.app.UiModeManager;
|
||||
import android.arch.persistence.room.Room;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
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.AppDatabase;
|
||||
import com.keylesspalace.tusky.di.AppInjector;
|
||||
import com.keylesspalace.tusky.util.OkHttpUtils;
|
||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
@ -40,13 +36,11 @@ import javax.inject.Inject;
|
|||
import dagger.android.AndroidInjector;
|
||||
import dagger.android.DispatchingAndroidInjector;
|
||||
import dagger.android.HasActivityInjector;
|
||||
import dagger.android.HasBroadcastReceiverInjector;
|
||||
import dagger.android.HasServiceInjector;
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
public class TuskyApplication extends Application implements HasActivityInjector, HasServiceInjector {
|
||||
public static final String APP_THEME_DEFAULT = ThemeUtils.THEME_NIGHT;
|
||||
|
||||
public class TuskyApplication extends Application implements HasActivityInjector, HasServiceInjector, HasBroadcastReceiverInjector {
|
||||
private static AppDatabase db;
|
||||
private AccountManager accountManager;
|
||||
@Inject
|
||||
|
@ -54,23 +48,19 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
|||
@Inject
|
||||
DispatchingAndroidInjector<Service> dispatchingServiceInjector;
|
||||
@Inject
|
||||
DispatchingAndroidInjector<BroadcastReceiver> dispatchingBroadcastReceiverInjector;
|
||||
@Inject
|
||||
NotificationPullJobCreator notificationPullJobCreator;
|
||||
@Inject OkHttpClient okHttpClient;
|
||||
|
||||
public static AppDatabase getDB() {
|
||||
return db;
|
||||
}
|
||||
|
||||
private static UiModeManager uiModeManager;
|
||||
|
||||
public static UiModeManager getUiModeManager() {
|
||||
return uiModeManager;
|
||||
}
|
||||
|
||||
public static TuskyApplication getInstance(@NonNull Context context) {
|
||||
return (TuskyApplication) context.getApplicationContext();
|
||||
}
|
||||
|
||||
|
||||
private ServiceLocator serviceLocator;
|
||||
|
||||
@Override
|
||||
|
@ -98,7 +88,6 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
|||
initPicasso();
|
||||
|
||||
JobManager.create(this).addJobCreator(notificationPullJobCreator);
|
||||
uiModeManager = (UiModeManager) getSystemService(Context.UI_MODE_SERVICE);
|
||||
|
||||
//necessary for Android < APi 21
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
|
@ -111,15 +100,7 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
|||
protected void initPicasso() {
|
||||
// Initialize Picasso configuration
|
||||
Picasso.Builder builder = new Picasso.Builder(this);
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
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()));
|
||||
builder.downloader(new OkHttp3Downloader(okHttpClient));
|
||||
if (BuildConfig.DEBUG) {
|
||||
builder.listener((picasso, uri, exception) -> exception.printStackTrace());
|
||||
}
|
||||
|
@ -141,6 +122,11 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
|||
return dispatchingServiceInjector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndroidInjector<BroadcastReceiver> broadcastReceiverInjector() {
|
||||
return dispatchingBroadcastReceiverInjector;
|
||||
}
|
||||
|
||||
public interface ServiceLocator {
|
||||
<T> T get(Class<T> clazz);
|
||||
}
|
||||
|
|
|
@ -61,6 +61,13 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector()
|
||||
abstract fun contributesAboutActivity(): AboutActivity
|
||||
|
||||
@ContributesAndroidInjector()
|
||||
abstract fun contributesLoginActivity(): LoginActivity
|
||||
|
||||
@ContributesAndroidInjector()
|
||||
abstract fun contributesSplashActivity(): SplashActivity
|
||||
|
||||
@ContributesAndroidInjector
|
||||
abstract fun contributesReportActivity(): ReportActivity
|
||||
|
||||
}
|
|
@ -32,7 +32,8 @@ import javax.inject.Singleton
|
|||
NetworkModule::class,
|
||||
AndroidInjectionModule::class,
|
||||
ActivitiesModule::class,
|
||||
ServicesModule::class
|
||||
ServicesModule::class,
|
||||
BroadcastReceiverModule::class
|
||||
])
|
||||
interface AppComponent {
|
||||
@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
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.content.Context
|
||||
import android.text.Spanned
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonDeserializer
|
||||
import com.keylesspalace.tusky.BuildConfig
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.json.SpannedTypeAdapter
|
||||
import com.keylesspalace.tusky.network.InstanceSwitchAuthInterceptor
|
||||
|
@ -31,8 +32,8 @@ import dagger.Provides
|
|||
import dagger.multibindings.ClassKey
|
||||
import dagger.multibindings.IntoMap
|
||||
import dagger.multibindings.IntoSet
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
|
@ -67,32 +68,24 @@ class NetworkModule {
|
|||
fun providesConverterFactory(gson: Gson): Converter.Factory = GsonConverterFactory.create(gson)
|
||||
|
||||
@Provides
|
||||
@IntoSet
|
||||
@Singleton
|
||||
fun providesAuthInterceptor(accountManager: AccountManager): Interceptor {
|
||||
// should accept AccountManager here probably but I don't want to break things yet
|
||||
return InstanceSwitchAuthInterceptor(accountManager)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesHttpClient(interceptors: @JvmSuppressWildcards Set<Interceptor>,
|
||||
preferences: SharedPreferences): OkHttpClient {
|
||||
return OkHttpUtils.getCompatibleClientBuilder(preferences)
|
||||
fun providesHttpClient(accountManager: AccountManager,
|
||||
context: Context): OkHttpClient {
|
||||
return OkHttpUtils.getCompatibleClientBuilder(context)
|
||||
.apply {
|
||||
interceptors.fold(this) { b, i ->
|
||||
b.addInterceptor(i)
|
||||
addInterceptor(InstanceSwitchAuthInterceptor(accountManager))
|
||||
if (BuildConfig.DEBUG) {
|
||||
addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC))
|
||||
}
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun providesRetrofit(httpClient: OkHttpClient,
|
||||
converters: @JvmSuppressWildcards Set<Converter.Factory>): Retrofit {
|
||||
return Retrofit.Builder().baseUrl("https://dummy.placeholder/")
|
||||
return Retrofit.Builder().baseUrl("https://"+MastodonApi.PLACEHOLDER_DOMAIN)
|
||||
.client(httpClient)
|
||||
.let { builder ->
|
||||
// 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.R;
|
||||
import com.keylesspalace.tusky.TuskyApplication;
|
||||
import com.keylesspalace.tusky.adapter.FooterViewHolder;
|
||||
import com.keylesspalace.tusky.adapter.NotificationsAdapter;
|
||||
import com.keylesspalace.tusky.db.AccountEntity;
|
||||
|
@ -108,6 +107,8 @@ public class NotificationsFragment extends SFragment implements
|
|||
public TimelineCases timelineCases;
|
||||
@Inject
|
||||
public MastodonApi mastodonApi;
|
||||
@Inject
|
||||
AccountManager accountManager;
|
||||
|
||||
private SwipeRefreshLayout swipeRefreshLayout;
|
||||
private LinearLayoutManager layoutManager;
|
||||
|
@ -606,8 +607,7 @@ public class NotificationsFragment extends SFragment implements
|
|||
}
|
||||
|
||||
private void saveNewestNotificationId(List<Notification> notifications) {
|
||||
AccountManager accountManager = TuskyApplication.getInstance(getContext())
|
||||
.getServiceLocator().get(AccountManager.class);
|
||||
|
||||
AccountEntity account = accountManager.getActiveAccount();
|
||||
BigInteger lastNoti = new BigInteger(account.getLastNotificationId());
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ public final class InstanceSwitchAuthInterceptor implements Interceptor {
|
|||
public Response intercept(@NonNull Chain chain) throws IOException {
|
||||
|
||||
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();
|
||||
|
||||
Request.Builder builder = originalRequest.newBuilder();
|
||||
|
@ -60,10 +63,14 @@ public final class InstanceSwitchAuthInterceptor implements Interceptor {
|
|||
Request newRequest = builder.build();
|
||||
|
||||
return chain.proceed(newRequest);
|
||||
|
||||
} else {
|
||||
return chain.proceed(originalRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ import retrofit2.http.Query;
|
|||
public interface MastodonApi {
|
||||
String ENDPOINT_AUTHORIZE = "/oauth/authorize";
|
||||
String DOMAIN_HEADER = "domain";
|
||||
String PLACEHOLDER_DOMAIN = "dummy.placeholder";
|
||||
|
||||
@GET("api/v1/timelines/home")
|
||||
Call<List<Status>> homeTimeline(
|
||||
|
@ -246,6 +247,7 @@ public interface MastodonApi {
|
|||
@FormUrlEncoded
|
||||
@POST("api/v1/apps")
|
||||
Call<AppCredentials> authenticateApp(
|
||||
@Header(DOMAIN_HEADER) String domain,
|
||||
@Field("client_name") String clientName,
|
||||
@Field("redirect_uris") String redirectUris,
|
||||
@Field("scopes") String scopes,
|
||||
|
@ -254,6 +256,7 @@ public interface MastodonApi {
|
|||
@FormUrlEncoded
|
||||
@POST("oauth/token")
|
||||
Call<AccessToken> fetchOAuthToken(
|
||||
@Header(DOMAIN_HEADER) String domain,
|
||||
@Field("client_id") String clientId,
|
||||
@Field("client_secret") String clientSecret,
|
||||
@Field("redirect_uri") String redirectUri,
|
||||
|
|
|
@ -19,17 +19,21 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
|
||||
import com.keylesspalace.tusky.TuskyApplication
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.util.NotificationHelper
|
||||
import dagger.android.AndroidInjection
|
||||
import javax.inject.Inject
|
||||
|
||||
class NotificationClearBroadcastReceiver : BroadcastReceiver() {
|
||||
|
||||
@Inject
|
||||
lateinit var accountManager: AccountManager
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
AndroidInjection.inject(this, context)
|
||||
|
||||
val accountId = intent.getLongExtra(NotificationHelper.ACCOUNT_ID, -1)
|
||||
|
||||
val accountManager = TuskyApplication.getInstance(context)
|
||||
.serviceLocator.get(AccountManager::class.java)
|
||||
val account = accountManager.getAccountById(accountId)
|
||||
if (account != null) {
|
||||
account.activeNotifications = "[]"
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
|
||||
package com.keylesspalace.tusky.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -43,11 +45,11 @@ import javax.net.ssl.TrustManager;
|
|||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
|
||||
public class OkHttpUtils {
|
||||
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.
|
||||
*/
|
||||
@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);
|
||||
String httpServer = preferences.getString("httpProxyServer", "");
|
||||
int httpPort = Integer.parseInt(preferences.getString("httpProxyPort", "-1"));
|
||||
|
@ -81,10 +87,13 @@ public class OkHttpUtils {
|
|||
specList.add(fallback);
|
||||
specList.add(ConnectionSpec.CLEARTEXT);
|
||||
|
||||
int cacheSize = 10*1024*1024; // 10 MiB
|
||||
|
||||
OkHttpClient.Builder builder = new OkHttpClient.Builder()
|
||||
.addInterceptor(getUserAgentInterceptor())
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.writeTimeout(30, TimeUnit.SECONDS)
|
||||
.cache(new Cache(context.getCacheDir(), cacheSize))
|
||||
.connectionSpecs(specList);
|
||||
|
||||
if (httpProxyEnabled && !httpServer.isEmpty() && (httpPort > 0) && (httpPort < 65535)) {
|
||||
|
@ -92,18 +101,9 @@ public class OkHttpUtils {
|
|||
builder.proxy(new Proxy(Proxy.Type.HTTP, address));
|
||||
}
|
||||
|
||||
if(BuildConfig.DEBUG) {
|
||||
builder.addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BASIC));
|
||||
}
|
||||
|
||||
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
|
||||
* Example:
|
||||
|
|
|
@ -30,13 +30,13 @@ import android.support.v7.app.AppCompatDelegate;
|
|||
import android.util.TypedValue;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.keylesspalace.tusky.TuskyApplication;
|
||||
|
||||
/**
|
||||
* Provides runtime compatibility to obtain theme information and re-theme views, especially where
|
||||
* the ability to do so is not supported in resource files.
|
||||
*/
|
||||
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_DAY = "day";
|
||||
public static final String THEME_AUTO = "auto";
|
||||
|
@ -91,7 +91,7 @@ public class ThemeUtils {
|
|||
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;
|
||||
switch (flavor) {
|
||||
default:
|
||||
|
@ -107,7 +107,8 @@ public class ThemeUtils {
|
|||
}
|
||||
|
||||
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 {
|
||||
AppCompatDelegate.setDefaultNightMode(mode);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue