From 0db1a23c4f362a4c0c5a8e5015d446f17bd43763 Mon Sep 17 00:00:00 2001 From: Bernd Date: Sat, 30 Mar 2019 15:18:16 +0100 Subject: [PATCH] Update Deps + Cleanup (#1158) * Fix Typo * Update build.gradle * Update Deps * Update Tests * Fixes Tests Without this some tests fail on my PC... + also: "Put this in your gradle.properties: android.enableUnitTestBinaryResources=true" from http://robolectric.org/migrating/#project-configuration * Make everything private * Fix Warning * Update TimelineFragment.java * Update build.gradle * Update gradle-wrapper.properties * Update gradle-wrapper.properties * Update gradle-wrapper.properties * Fix Compile Errors e.g. Type inference failed. Expected type mismatch: inferred type is Preference? but Preference was expected Type inference failed. Please try to specify type arguments explicitly. * fix crash * Grandle Wrapper 5.3 * Revert "Fix Compile Errors" This reverts commit 4a774a4fe3ce82c84bd7b4d78e1a1c64af97cd0d. * requirePreference * oops * Cleanup * Update gradle-wrapper.properties --- app/build.gradle | 11 ++++---- .../com/keylesspalace/tusky/MigrationsTest.kt | 2 +- .../keylesspalace/tusky/TimelineDAOTest.kt | 2 +- .../tusky/fragment/TimelineFragment.java | 7 ++--- .../preference/AccountPreferencesFragment.kt | 24 +++++++++--------- .../NotificationPreferencesFragment.kt | 16 ++++++------ .../preference/PreferencesFragment.kt | 18 ++++++++----- .../preference/ProxyPreferencesFragment.kt | 3 ++- .../tusky/BottomSheetActivityTest.kt | 2 +- .../tusky/ComposeActivityTest.kt | 16 ++++++------ .../tusky/FakeTuskyApplication.kt | 2 +- .../com/keylesspalace/tusky/SpanUtilsTest.kt | 2 +- .../tusky/fragment/TimelineRepositoryTest.kt | 14 +++++----- build.gradle | 2 +- gradle.properties | 1 + gradle/wrapper/gradle-wrapper.jar | Bin 55190 -> 55616 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 18 ++++++++++++- gradlew.bat | 18 ++++++++++++- 19 files changed, 99 insertions(+), 61 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 6f7f52ea..4c96f21f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -95,14 +95,14 @@ dependencies { implementation 'com.google.android.material:material:1.1.0-alpha04' implementation 'androidx.exifinterface:exifinterface:1.0.0' implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.preference:preference:1.1.0-alpha03' + implementation 'androidx.preference:preference:1.1.0-alpha04' implementation 'com.squareup.retrofit2:retrofit:2.5.0' implementation 'com.squareup.retrofit2:converter-gson:2.5.0' implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0' implementation 'com.squareup.picasso:picasso:2.5.2' implementation 'com.squareup.okhttp3:okhttp:3.13.1' implementation 'com.squareup.okhttp3:logging-interceptor:3.13.1' - implementation "org.conscrypt:conscrypt-android:2.0.0" + implementation 'org.conscrypt:conscrypt-android:2.0.0' implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0' implementation 'com.github.connyduck:sparkbutton:2.0.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0' @@ -130,13 +130,12 @@ dependencies { kapt "com.google.dagger:dagger-android-processor:$daggerVersion" testImplementation 'org.robolectric:robolectric:4.2' testImplementation 'org.mockito:mockito-inline:2.24.0' - testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0" + testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0' androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) - androidTestImplementation('android.arch.persistence.room:testing:1.1.1') - androidTestImplementation "androidx.test.ext:junit:1.1.0" - testImplementation "androidx.test.ext:junit:1.1.0" + androidTestImplementation 'android.arch.persistence.room:testing:1.1.1' + testImplementation 'androidx.test.ext:junit:1.1.0' debugImplementation 'im.dino:dbinspector:3.4.1@aar' implementation 'io.reactivex.rxjava2:rxjava:2.2.6' implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' diff --git a/app/src/androidTest/java/com/keylesspalace/tusky/MigrationsTest.kt b/app/src/androidTest/java/com/keylesspalace/tusky/MigrationsTest.kt index b7f5c0b0..d44860f8 100644 --- a/app/src/androidTest/java/com/keylesspalace/tusky/MigrationsTest.kt +++ b/app/src/androidTest/java/com/keylesspalace/tusky/MigrationsTest.kt @@ -10,7 +10,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -const val TEST_DB = "mirgation_test" +const val TEST_DB = "migration_test" @RunWith(AndroidJUnit4::class) class MigrationsTest { diff --git a/app/src/androidTest/java/com/keylesspalace/tusky/TimelineDAOTest.kt b/app/src/androidTest/java/com/keylesspalace/tusky/TimelineDAOTest.kt index 51b50ba5..4edf759a 100644 --- a/app/src/androidTest/java/com/keylesspalace/tusky/TimelineDAOTest.kt +++ b/app/src/androidTest/java/com/keylesspalace/tusky/TimelineDAOTest.kt @@ -182,7 +182,7 @@ class TimelineDAOTest { return Triple(status, author, reblogAuthor) } - fun createPlaceholder(serverId: String, timelineUserId: Long): TimelineStatusEntity { + private fun createPlaceholder(serverId: String, timelineUserId: Long): TimelineStatusEntity { return TimelineStatusEntity( serverId = serverId, url = null, diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java index 51004c6a..8e3ee76f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/TimelineFragment.java @@ -135,7 +135,7 @@ public class TimelineFragment extends SFragment implements @Inject public EventHub eventHub; @Inject - public TimelineRepository timelineRepo; + TimelineRepository timelineRepo; @Inject public AccountManager accountManager; @@ -1102,9 +1102,10 @@ public class TimelineFragment extends SFragment implements Either lastOfNew = newStatuses.get(newStatuses.size() - 1); int index = statuses.indexOf(lastOfNew); - for (int i = 0; i < index; i++) { - statuses.remove(0); + if (index >= 0) { + statuses.subList(0, index).clear(); } + int newIndex = newStatuses.indexOf(statuses.get(0)); if (newIndex == -1) { if (index == -1 && fullFetch) { diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/AccountPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/AccountPreferencesFragment.kt index 3c7ea6d9..c3293bd1 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/AccountPreferencesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/AccountPreferencesFragment.kt @@ -76,18 +76,18 @@ class AccountPreferencesFragment : PreferenceFragmentCompat(), override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.account_preferences) - notificationPreference = findPreference("notificationPreference") - tabPreference = findPreference("tabPreference") - mutedUsersPreference = findPreference("mutedUsersPreference") - blockedUsersPreference = findPreference("blockedUsersPreference") - defaultPostPrivacyPreference = findPreference("defaultPostPrivacy") as ListPreference - defaultMediaSensitivityPreference = findPreference("defaultMediaSensitivity") as SwitchPreference - mediaPreviewEnabledPreference = findPreference("mediaPreviewEnabled") as SwitchPreference - alwaysShowSensitiveMediaPreference = findPreference("alwaysShowSensitiveMedia") as SwitchPreference - homeFiltersPreference = findPreference("homeFilters") - notificationFiltersPreference = findPreference("notificationFilters") - publicFiltersPreference = findPreference("publicFilters") - threadFiltersPreference = findPreference("threadFilters") + notificationPreference = requirePreference("notificationPreference") + tabPreference = requirePreference("tabPreference") + mutedUsersPreference = requirePreference("mutedUsersPreference") + blockedUsersPreference = requirePreference("blockedUsersPreference") + defaultPostPrivacyPreference = requirePreference("defaultPostPrivacy") as ListPreference + defaultMediaSensitivityPreference = requirePreference("defaultMediaSensitivity") as SwitchPreference + mediaPreviewEnabledPreference = requirePreference("mediaPreviewEnabled") as SwitchPreference + alwaysShowSensitiveMediaPreference = requirePreference("alwaysShowSensitiveMedia") as SwitchPreference + homeFiltersPreference = requirePreference("homeFilters") + notificationFiltersPreference = requirePreference("notificationFilters") + publicFiltersPreference = requirePreference("publicFilters") + threadFiltersPreference = requirePreference("threadFilters") notificationPreference.icon = IconicsDrawable(notificationPreference.context, GoogleMaterial.Icon.gmd_notifications).sizePx(iconSize).color(ThemeUtils.getColor(notificationPreference.context, R.attr.toolbar_icon_tint)) mutedUsersPreference.icon = getTintedIcon(R.drawable.ic_mute_24dp) diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/NotificationPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/NotificationPreferencesFragment.kt index 104b9f3d..4c62e0fa 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/NotificationPreferencesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/NotificationPreferencesFragment.kt @@ -42,35 +42,35 @@ class NotificationPreferencesFragment : PreferenceFragmentCompat(), Preference.O if (activeAccount != null) { - val notificationPref = findPreference("notificationsEnabled") as SwitchPreference + val notificationPref = requirePreference("notificationsEnabled") as SwitchPreference notificationPref.isChecked = activeAccount.notificationsEnabled notificationPref.onPreferenceChangeListener = this - val mentionedPref = findPreference("notificationFilterMentions") as SwitchPreference + val mentionedPref = requirePreference("notificationFilterMentions") as SwitchPreference mentionedPref.isChecked = activeAccount.notificationsMentioned mentionedPref.onPreferenceChangeListener = this - val followedPref = findPreference("notificationFilterFollows") as SwitchPreference + val followedPref = requirePreference("notificationFilterFollows") as SwitchPreference followedPref.isChecked = activeAccount.notificationsFollowed followedPref.onPreferenceChangeListener = this - val boostedPref = findPreference("notificationFilterReblogs") as SwitchPreference + val boostedPref = requirePreference("notificationFilterReblogs") as SwitchPreference boostedPref.isChecked = activeAccount.notificationsReblogged boostedPref.onPreferenceChangeListener = this - val favoritedPref = findPreference("notificationFilterFavourites") as SwitchPreference + val favoritedPref = requirePreference("notificationFilterFavourites") as SwitchPreference favoritedPref.isChecked = activeAccount.notificationsFavorited favoritedPref.onPreferenceChangeListener = this - val soundPref = findPreference("notificationAlertSound") as SwitchPreference + val soundPref = requirePreference("notificationAlertSound") as SwitchPreference soundPref.isChecked = activeAccount.notificationSound soundPref.onPreferenceChangeListener = this - val vibrationPref = findPreference("notificationAlertVibrate") as SwitchPreference + val vibrationPref = requirePreference("notificationAlertVibrate") as SwitchPreference vibrationPref.isChecked = activeAccount.notificationVibration vibrationPref.onPreferenceChangeListener = this - val lightPref = findPreference("notificationAlertLight") as SwitchPreference + val lightPref = requirePreference("notificationAlertLight") as SwitchPreference lightPref.isChecked = activeAccount.notificationLight lightPref.onPreferenceChangeListener = this } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/PreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/PreferencesFragment.kt index 20e0edb0..6303514e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/PreferencesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/PreferencesFragment.kt @@ -25,6 +25,10 @@ import com.keylesspalace.tusky.util.getNonNullString import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.IconicsDrawable +fun PreferenceFragmentCompat.requirePreference(key: String): Preference { + return findPreference(key)!! +} + class PreferencesFragment : PreferenceFragmentCompat() { private val iconSize by lazy {resources.getDimensionPixelSize(R.dimen.preference_icon_size)} @@ -33,16 +37,16 @@ class PreferencesFragment : PreferenceFragmentCompat() { addPreferencesFromResource(R.xml.preferences) - val themePreference: Preference = findPreference("appTheme") + val themePreference: Preference = requirePreference("appTheme") themePreference.icon = IconicsDrawable(themePreference.context, GoogleMaterial.Icon.gmd_palette).sizePx(iconSize).color(ThemeUtils.getColor(themePreference.context, R.attr.toolbar_icon_tint)) - val emojiPreference: Preference = findPreference("emojiCompat") + val emojiPreference: Preference = requirePreference("emojiCompat") emojiPreference.icon = IconicsDrawable(emojiPreference.context, GoogleMaterial.Icon.gmd_sentiment_satisfied).sizePx(iconSize).color(ThemeUtils.getColor(emojiPreference.context, R.attr.toolbar_icon_tint)) - val textSizePreference: Preference = findPreference("statusTextSize") + val textSizePreference: Preference = requirePreference("statusTextSize") textSizePreference.icon = IconicsDrawable(textSizePreference.context, GoogleMaterial.Icon.gmd_format_size).sizePx(iconSize).color(ThemeUtils.getColor(textSizePreference.context, R.attr.toolbar_icon_tint)) - val timelineFilterPreferences: Preference = findPreference("timelineFilterPreferences") + val timelineFilterPreferences: Preference = requirePreference("timelineFilterPreferences") timelineFilterPreferences.setOnPreferenceClickListener { activity?.let { activity -> val intent = PreferencesActivity.newIntent(activity, PreferencesActivity.TAB_FILTER_PREFERENCES) @@ -52,7 +56,7 @@ class PreferencesFragment : PreferenceFragmentCompat() { true } - val httpProxyPreferences: Preference = findPreference("httpProxyPreferences") + val httpProxyPreferences: Preference = requirePreference("httpProxyPreferences") httpProxyPreferences.setOnPreferenceClickListener { activity?.let { activity -> val intent = PreferencesActivity.newIntent(activity, PreferencesActivity.PROXY_PREFERENCES) @@ -62,7 +66,7 @@ class PreferencesFragment : PreferenceFragmentCompat() { true } - val languagePreference: Preference = findPreference("language") + val languagePreference: Preference = requirePreference("language") languagePreference.icon = IconicsDrawable(languagePreference.context, GoogleMaterial.Icon.gmd_translate).sizePx(iconSize).color(ThemeUtils.getColor(languagePreference.context, R.attr.toolbar_icon_tint)) } @@ -73,7 +77,7 @@ class PreferencesFragment : PreferenceFragmentCompat() { private fun updateHttpProxySummary() { - val httpProxyPref: Preference = findPreference("httpProxyPreferences") + val httpProxyPref: Preference = requirePreference("httpProxyPreferences") val sharedPreferences = preferenceManager.sharedPreferences diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/ProxyPreferencesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/ProxyPreferencesFragment.kt index 4c7c8726..64403539 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/preference/ProxyPreferencesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/preference/ProxyPreferencesFragment.kt @@ -18,6 +18,7 @@ package com.keylesspalace.tusky.fragment.preference import android.content.SharedPreferences import android.os.Bundle import androidx.preference.EditTextPreference +import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import com.keylesspalace.tusky.R @@ -61,7 +62,7 @@ class ProxyPreferencesFragment : PreferenceFragmentCompat(), SharedPreferences.O private fun updateSummary(key: String) { when (key) { "httpProxyServer", "httpProxyPort" -> { - val editTextPreference = findPreference(key) as EditTextPreference + val editTextPreference = requirePreference(key) as EditTextPreference editTextPreference.summary = editTextPreference.text } } diff --git a/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt index e0a377d4..baa78b69 100644 --- a/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/BottomSheetActivityTest.kt @@ -99,7 +99,7 @@ class BottomSheetActivityTest { } @RunWith(Parameterized::class) - class UrlMatchingTests(val url: String, val expectedResult: Boolean) { + class UrlMatchingTests(private val url: String, private val expectedResult: Boolean) { companion object { @Parameterized.Parameters(name = "match_{0}") @JvmStatic diff --git a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt index 754dc238..12522908 100644 --- a/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/ComposeActivityTest.kt @@ -38,7 +38,7 @@ import org.mockito.Mockito import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import org.robolectric.Robolectric -import org.robolectric.RobolectricTestRunner +import androidx.test.ext.junit.runners.AndroidJUnit4 import org.robolectric.annotation.Config import org.robolectric.fakes.RoboMenuItem import retrofit2.Call @@ -51,15 +51,15 @@ import retrofit2.Response */ @Config(application = FakeTuskyApplication::class) -@RunWith(RobolectricTestRunner::class) +@RunWith(AndroidJUnit4::class) class ComposeActivityTest { - lateinit var activity: ComposeActivity - lateinit var accountManagerMock: AccountManager - lateinit var apiMock: MastodonApi - lateinit var themeUtilsMock: ThemeUtils + private lateinit var activity: ComposeActivity + private lateinit var accountManagerMock: AccountManager + private lateinit var apiMock: MastodonApi + private lateinit var themeUtilsMock: ThemeUtils - val account = AccountEntity( + private val account = AccountEntity( id = 1, domain = "example.token", accessToken = "token", @@ -259,7 +259,7 @@ class ComposeActivityTest { "Example instance for testing", "admin@example.token", "2.6.3", - HashMap(), + HashMap(), null, null, listOf("en"), diff --git a/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt b/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt index 6337228a..30c40d5a 100644 --- a/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt +++ b/app/src/test/java/com/keylesspalace/tusky/FakeTuskyApplication.kt @@ -6,7 +6,7 @@ package com.keylesspalace.tusky class FakeTuskyApplication : TuskyApplication() { - lateinit var locator: ServiceLocator + private lateinit var locator: ServiceLocator override fun initSecurityProvider() { // No-op diff --git a/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt b/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt index 3b4f5c10..37e3a1be 100644 --- a/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/SpanUtilsTest.kt @@ -105,7 +105,7 @@ class SpanUtilsTest { ArrayList() } else { spans.filter { it.start >= start && it.end <= end && type.isAssignableFrom(it.span?.javaClass) } - .map { it -> it.span } + .map { it.span } .let { ArrayList(it) } } return matching.toArray() as Array diff --git a/app/src/test/java/com/keylesspalace/tusky/fragment/TimelineRepositoryTest.kt b/app/src/test/java/com/keylesspalace/tusky/fragment/TimelineRepositoryTest.kt index c29e9e62..68853de1 100644 --- a/app/src/test/java/com/keylesspalace/tusky/fragment/TimelineRepositoryTest.kt +++ b/app/src/test/java/com/keylesspalace/tusky/fragment/TimelineRepositoryTest.kt @@ -39,23 +39,23 @@ class TimelineRepositoryTest { lateinit var mastodonApi: MastodonApi @Mock - lateinit var accountManager: AccountManager + private lateinit var accountManager: AccountManager - lateinit var gson: Gson + private lateinit var gson: Gson - lateinit var subject: TimelineRepository + private lateinit var subject: TimelineRepository - lateinit var testScheduler: TestScheduler + private lateinit var testScheduler: TestScheduler - val limit = 30 - val account = AccountEntity( + private val limit = 30 + private val account = AccountEntity( id = 2, accessToken = "token", domain = "domain.com", isActive = true ) - val htmlConverter = object : HtmlConverter { + private val htmlConverter = object : HtmlConverter { override fun fromHtml(html: String): Spanned { return SpanUtilsTest.FakeSpannable(html) } diff --git a/build.gradle b/build.gradle index 6b309c53..8056f6e6 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta02' + classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta04' classpath 'com.android.tools.build:gradle:3.3.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } diff --git a/gradle.properties b/gradle.properties index 8e49a065..e28b800e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,3 +17,4 @@ org.gradle.parallel=true android.enableJetifier=true android.useAndroidX=true +android.enableUnitTestBinaryResources=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 87b738cbd051603d91cc39de6cb000dd98fe6b02..5c2d1cf016b3885f6930543d57b744ea8c220a1a 100644 GIT binary patch delta 3320 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