From 817b6ac99e3f309bcdacdeebb6becf636ee28b11 Mon Sep 17 00:00:00 2001 From: Janne Koschinski <janne@kuschku.de> Date: Mon, 13 May 2019 19:06:59 +0200 Subject: [PATCH] Prepare for UI tests --- .gitlab-ci.yml | 2 +- app/build.gradle.kts | 8 + .../quasseldroid/AccountBehaviorTest.kt | 171 ++++++++++++++++++ .../quasseldroid/ActivityLifecycleHandler.kt | 43 +++++ .../quasseldroid/QuasseldroidAndroidTest.kt | 33 ++++ .../kuschku/quasseldroid/util/TestRunner.kt | 38 ++++ .../de/kuschku/quasseldroid/util/ViewUtil.kt | 26 +++ .../conditionwatcher/ConditionWatcher.java | 82 +++++++++ .../util/conditionwatcher/Instruction.kt | 38 ++++ .../util/matcher/IsFullyRenderedMatcher.kt | 51 ++++++ .../de/kuschku/quasseldroid/Quasseldroid.kt | 3 +- .../kuschku/quasseldroid/app/AppDelegate.kt | 3 +- .../app/QuasseldroidBaseDelegate.kt | 54 ++++++ .../app/QuasseldroidReleaseDelegate.kt | 37 +--- .../accounts/selection/AccountAdapter.kt | 12 +- .../app/QuasseldroidTestDelegate.kt | 3 +- 16 files changed, 562 insertions(+), 42 deletions(-) create mode 100644 app/src/androidTest/java/de/kuschku/quasseldroid/AccountBehaviorTest.kt create mode 100644 app/src/androidTest/java/de/kuschku/quasseldroid/ActivityLifecycleHandler.kt create mode 100644 app/src/androidTest/java/de/kuschku/quasseldroid/QuasseldroidAndroidTest.kt create mode 100644 app/src/androidTest/java/de/kuschku/quasseldroid/util/TestRunner.kt create mode 100644 app/src/androidTest/java/de/kuschku/quasseldroid/util/ViewUtil.kt create mode 100644 app/src/androidTest/java/de/kuschku/quasseldroid/util/conditionwatcher/ConditionWatcher.java create mode 100644 app/src/androidTest/java/de/kuschku/quasseldroid/util/conditionwatcher/Instruction.kt create mode 100644 app/src/androidTest/java/de/kuschku/quasseldroid/util/matcher/IsFullyRenderedMatcher.kt create mode 100644 app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidBaseDelegate.kt diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f5502c247..f78f4eefa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,7 +35,7 @@ build: test: stage: "test" script: - - "./gradlew check" + - "./gradlew check -x connectedCheck" artifacts: reports: junit: "*/build/test-results/*/TEST-*.xml" diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ab8a77718..afa441c01 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -61,6 +61,7 @@ android { testInstrumentationRunnerArguments = mapOf( "disableAnalytics" to "true" ) + testInstrumentationRunner = "de.kuschku.quasseldroid.util.TestRunner" } buildTypes { @@ -188,4 +189,11 @@ dependencies { testImplementation("org.robolectric", "robolectric", "4.2") { exclude(group = "org.threeten", module = "threetenbp") } + + androidTestImplementation("junit", "junit", "4.12") + androidTestImplementation("androidx.test.espresso", "espresso-core", "3.1.0") + androidTestImplementation("androidx.test.espresso", "espresso-contrib", "3.1.0") + androidTestImplementation("androidx.test.ext", "junit", "1.1.0") + androidTestImplementation("androidx.test", "runner", "1.1.0") + androidTestImplementation("androidx.test", "rules", "1.1.0") } diff --git a/app/src/androidTest/java/de/kuschku/quasseldroid/AccountBehaviorTest.kt b/app/src/androidTest/java/de/kuschku/quasseldroid/AccountBehaviorTest.kt new file mode 100644 index 000000000..859ec8dd9 --- /dev/null +++ b/app/src/androidTest/java/de/kuschku/quasseldroid/AccountBehaviorTest.kt @@ -0,0 +1,171 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid + +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.* +import androidx.test.espresso.contrib.RecyclerViewActions +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.ActivityTestRule +import com.google.android.material.floatingactionbutton.FloatingActionButton +import com.google.android.material.textfield.TextInputEditText +import de.kuschku.quasseldroid.ui.chat.ChatActivity +import de.kuschku.quasseldroid.ui.setup.accounts.selection.AccountSelectionActivity +import de.kuschku.quasseldroid.util.conditionwatcher.ConditionWatcher.waitForCondition +import de.kuschku.quasseldroid.util.conditionwatcher.Instruction +import de.kuschku.quasseldroid.util.matcher.IsFullyRenderedMatcher.Companion.isFullyRendered +import de.kuschku.quasseldroid.util.matches +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import java.lang.Thread.sleep + + +@RunWith(AndroidJUnit4::class) +@LargeTest +class AccountBehaviorTest { + @get:Rule + val activityActivityTestRule = ActivityTestRule(ChatActivity::class.java) + + data class TestData( + val host: String, + val port: Int, + val requireSsl: Boolean, + val user: String, + val pass: String + ) + + @Test + fun actuallyTestThisThing() { + val testData = TestData( + host = InstrumentationRegistry.getArguments().getString("host", "localhost"), + port = InstrumentationRegistry.getArguments().getInt("port", 4242), + requireSsl = InstrumentationRegistry.getArguments().getBoolean("requireSsl"), + user = InstrumentationRegistry.getArguments().getString("user", "test"), + pass = InstrumentationRegistry.getArguments().getString("pass", "test") + ) + + onView(withId(R.id.host)) + .perform(typeText(testData.host)) + + onView(withId(R.id.port)) + .perform( + clearText(), + typeText(testData.port.toString()) + ) + + if (testData.requireSsl) { + onView(withId(R.id.require_ssl)) + .perform(click()) + } + + waitForCondition(1_000, Instruction("next button should be visible") { + activity?.findViewById<FloatingActionButton>(R.id.next_button).matches( + isFullyRendered() + ) + }) + + onView(withId(R.id.next_button)) + .perform(click()) + + waitForCondition(1_000, Instruction("user input should be visible") { + activity?.findViewById<TextInputEditText>(R.id.user).matches( + isFullyRendered() + ) + }) + + onView(withId(R.id.user)) + .perform( + clearText(), + typeText(testData.user) + ) + + onView(withId(R.id.pass)) + .perform( + clearText(), + typeText(testData.pass) + ) + + waitForCondition(1_000, Instruction("next button should be visible") { + activity?.findViewById<FloatingActionButton>(R.id.next_button).matches( + isFullyRendered() + ) + }) + + onView(withId(R.id.next_button)) + .perform(click()) + + waitForCondition(1_000, Instruction("name input should be visible") { + activity?.findViewById<TextInputEditText>(R.id.name).matches( + isFullyRendered() + ) + }) + + onView(withId(R.id.name)) + .perform( + clearText(), + typeText("Remote Test") + ) + + waitForCondition(1_000, Instruction("next button should be visible") { + activity?.findViewById<FloatingActionButton>(R.id.next_button).matches( + isFullyRendered() + ) + }) + + onView(withId(R.id.next_button)) + .perform(click()) + + waitForCondition(1_000, Instruction("selection activity should be shown") { + activity is AccountSelectionActivity + }) + + sleep(500) + + onView(withId(R.id.account_list)) + .perform(RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(0, click())) + + waitForCondition(1_000, Instruction("next button should be visible") { + activity?.findViewById<FloatingActionButton>(R.id.next_button).matches( + isFullyRendered() + ) + }) + + onView(withId(R.id.next_button)) + .perform(click()) + + waitForCondition(1_000, Instruction("chat activity should be shown") { + activity is ChatActivity + }) + + waitForCondition(10_000, Instruction("connection display should not be shown") { + activity?.findViewById<View>(R.id.connection_status).matches( + withEffectiveVisibility(ViewMatchers.Visibility.GONE) + ) + }) + } +} diff --git a/app/src/androidTest/java/de/kuschku/quasseldroid/ActivityLifecycleHandler.kt b/app/src/androidTest/java/de/kuschku/quasseldroid/ActivityLifecycleHandler.kt new file mode 100644 index 000000000..26a011c8c --- /dev/null +++ b/app/src/androidTest/java/de/kuschku/quasseldroid/ActivityLifecycleHandler.kt @@ -0,0 +1,43 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid + +import android.app.Activity +import android.app.Application +import android.os.Bundle + +class ActivityLifecycleHandler : Application.ActivityLifecycleCallbacks { + var currentActivity: Activity? = null + private set + + override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) = Unit + override fun onActivityStarted(activity: Activity?) = Unit + override fun onActivityResumed(activity: Activity?) { + currentActivity = activity + } + + override fun onActivityPaused(activity: Activity?) { + currentActivity = null + } + + override fun onActivityStopped(activity: Activity?) = Unit + override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) = Unit + override fun onActivityDestroyed(activity: Activity?) = Unit +} diff --git a/app/src/androidTest/java/de/kuschku/quasseldroid/QuasseldroidAndroidTest.kt b/app/src/androidTest/java/de/kuschku/quasseldroid/QuasseldroidAndroidTest.kt new file mode 100644 index 000000000..baa3637b6 --- /dev/null +++ b/app/src/androidTest/java/de/kuschku/quasseldroid/QuasseldroidAndroidTest.kt @@ -0,0 +1,33 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid + +import de.kuschku.quasseldroid.app.QuasseldroidBaseDelegate + +class QuasseldroidAndroidTest : Quasseldroid() { + val activityLifecycleHandler = ActivityLifecycleHandler() + + override val delegate = QuasseldroidBaseDelegate(this) + + override fun onCreate() { + super.onCreate() + registerActivityLifecycleCallbacks(activityLifecycleHandler) + } +} diff --git a/app/src/androidTest/java/de/kuschku/quasseldroid/util/TestRunner.kt b/app/src/androidTest/java/de/kuschku/quasseldroid/util/TestRunner.kt new file mode 100644 index 000000000..b40394b85 --- /dev/null +++ b/app/src/androidTest/java/de/kuschku/quasseldroid/util/TestRunner.kt @@ -0,0 +1,38 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.util + +import android.app.Application +import android.content.Context +import androidx.test.runner.AndroidJUnitRunner +import de.kuschku.quasseldroid.Quasseldroid +import de.kuschku.quasseldroid.QuasseldroidAndroidTest + +class TestRunner : AndroidJUnitRunner() { + override fun newApplication(cl: ClassLoader?, className: String?, + context: Context?): Application { + return super.newApplication( + cl, + if (className == Quasseldroid::class.java.canonicalName) QuasseldroidAndroidTest::class.java.canonicalName + else className, + context + ) + } +} diff --git a/app/src/androidTest/java/de/kuschku/quasseldroid/util/ViewUtil.kt b/app/src/androidTest/java/de/kuschku/quasseldroid/util/ViewUtil.kt new file mode 100644 index 000000000..898a91bc6 --- /dev/null +++ b/app/src/androidTest/java/de/kuschku/quasseldroid/util/ViewUtil.kt @@ -0,0 +1,26 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.util + +import org.hamcrest.Matcher + +fun <T> T?.matches(vararg matchers: Matcher<T>): Boolean = this != null && matchers.all { + it.matches(this) +} diff --git a/app/src/androidTest/java/de/kuschku/quasseldroid/util/conditionwatcher/ConditionWatcher.java b/app/src/androidTest/java/de/kuschku/quasseldroid/util/conditionwatcher/ConditionWatcher.java new file mode 100644 index 000000000..dd94f4403 --- /dev/null +++ b/app/src/androidTest/java/de/kuschku/quasseldroid/util/conditionwatcher/ConditionWatcher.java @@ -0,0 +1,82 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.util.conditionwatcher; + +/** + * Created by F1sherKK on 08/10/15. + */ +public class ConditionWatcher { + + public static final int CONDITION_NOT_MET = 0; + public static final int CONDITION_MET = 1; + public static final int TIMEOUT = 2; + + public static final int DEFAULT_TIMEOUT_LIMIT = 1000 * 60; + public static final int DEFAULT_INTERVAL = 250; + private static ConditionWatcher conditionWatcher; + private int timeoutLimit = DEFAULT_TIMEOUT_LIMIT; + private int watchInterval = DEFAULT_INTERVAL; + + private ConditionWatcher() { + super(); + } + + public static ConditionWatcher getInstance() { + if (conditionWatcher == null) { + conditionWatcher = new ConditionWatcher(); + } + return conditionWatcher; + } + + public static void waitForCondition(int timeoutLimit, Instruction instruction) throws Exception { + setTimeoutLimit(timeoutLimit); + waitForCondition(instruction); + } + + public static void waitForCondition(Instruction instruction) throws Exception { + int status = CONDITION_NOT_MET; + int elapsedTime = 0; + + do { + if (instruction.checkCondition()) { + status = CONDITION_MET; + } else { + elapsedTime += getInstance().watchInterval; + Thread.sleep(getInstance().watchInterval); + } + + if (elapsedTime >= getInstance().timeoutLimit) { + status = TIMEOUT; + break; + } + } while (status != CONDITION_MET); + + if (status == TIMEOUT) + throw new Exception(instruction.getDescription() + " - took more than " + getInstance().timeoutLimit / 1000 + " seconds. Test stopped."); + } + + public static void setWatchInterval(int watchInterval) { + getInstance().watchInterval = watchInterval; + } + + public static void setTimeoutLimit(int ms) { + getInstance().timeoutLimit = ms; + } +} diff --git a/app/src/androidTest/java/de/kuschku/quasseldroid/util/conditionwatcher/Instruction.kt b/app/src/androidTest/java/de/kuschku/quasseldroid/util/conditionwatcher/Instruction.kt new file mode 100644 index 000000000..44f12d0a2 --- /dev/null +++ b/app/src/androidTest/java/de/kuschku/quasseldroid/util/conditionwatcher/Instruction.kt @@ -0,0 +1,38 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.util.conditionwatcher + +import androidx.test.platform.app.InstrumentationRegistry +import de.kuschku.quasseldroid.QuasseldroidAndroidTest + +class Instruction( + val description: String, + private val condition: InstructionContext.() -> Boolean +) { + fun checkCondition(): Boolean = condition.invoke(InstructionContext) + + object InstructionContext { + val application + get() = (InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as QuasseldroidAndroidTest) + + val activity + get() = application.activityLifecycleHandler.currentActivity + } +} diff --git a/app/src/androidTest/java/de/kuschku/quasseldroid/util/matcher/IsFullyRenderedMatcher.kt b/app/src/androidTest/java/de/kuschku/quasseldroid/util/matcher/IsFullyRenderedMatcher.kt new file mode 100644 index 000000000..dbf0793fd --- /dev/null +++ b/app/src/androidTest/java/de/kuschku/quasseldroid/util/matcher/IsFullyRenderedMatcher.kt @@ -0,0 +1,51 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.util.matcher + +import android.view.View +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.remote.annotation.RemoteMsgConstructor +import de.kuschku.quasseldroid.util.matches +import org.hamcrest.Description +import org.hamcrest.TypeSafeMatcher + +class IsFullyRenderedMatcher @RemoteMsgConstructor internal constructor( + areaPercentage: Int +) : TypeSafeMatcher<View>() { + + private val isDisplayingAtLeastMatcher = ViewMatchers.isDisplayingAtLeast( + areaPercentage) + private val withEffectiveVisibilityMatcher = ViewMatchers.withEffectiveVisibility( + ViewMatchers.Visibility.VISIBLE) + + override fun describeTo(description: Description) { + description.appendText("view is fully rendered") + } + + public override fun matchesSafely(view: View) = view.matches( + isDisplayingAtLeastMatcher, + withEffectiveVisibilityMatcher + ) + + companion object { + fun isFullyRendered(areaPercentage: Int = 100) = IsFullyRenderedMatcher( + areaPercentage) + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt b/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt index 747366f5b..59d1f81e1 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/Quasseldroid.kt @@ -34,6 +34,7 @@ open class Quasseldroid : DaggerApplication() { super.onCreate() if (delegate.shouldInit()) { delegate.onInit() + delegate.onPreInit() applicationInjector().inject(this) delegate.onPostInit() } @@ -41,6 +42,6 @@ open class Quasseldroid : DaggerApplication() { override fun attachBaseContext(base: Context) { super.attachBaseContext(LocaleHelper.setLocale(base)) - delegate.onInstallMultidex() + delegate.onAttachBaseContext() } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/app/AppDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid/app/AppDelegate.kt index 482bb3550..2732e3d9f 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/app/AppDelegate.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/app/AppDelegate.kt @@ -21,7 +21,8 @@ package de.kuschku.quasseldroid.app interface AppDelegate { fun shouldInit(): Boolean - fun onInstallMultidex() + fun onAttachBaseContext() + fun onPreInit() fun onInit() fun onPostInit() } diff --git a/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidBaseDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidBaseDelegate.kt new file mode 100644 index 000000000..2ae5e248e --- /dev/null +++ b/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidBaseDelegate.kt @@ -0,0 +1,54 @@ +/* + * Quasseldroid - Quassel client for Android + * + * Copyright (c) 2019 Janne Koschinski + * Copyright (c) 2019 The Quassel Project + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. + */ + +package de.kuschku.quasseldroid.app + +import androidx.appcompat.app.AppCompatDelegate +import androidx.multidex.MultiDex +import de.kuschku.quasseldroid.BuildConfig +import de.kuschku.quasseldroid.Quasseldroid +import de.kuschku.quasseldroid.util.backport.AndroidThreeTenBackport +import de.kuschku.quasseldroid.util.compatibility.AndroidCompatibilityUtils +import de.kuschku.quasseldroid.util.compatibility.AndroidLoggingHandler +import de.kuschku.quasseldroid.util.compatibility.AndroidStreamChannelFactory + +open class QuasseldroidBaseDelegate(private val app: Quasseldroid) : AppDelegate { + override fun shouldInit() = true + + override fun onPreInit() = Unit + + override fun onInit() { + // Init compatibility utils + AndroidCompatibilityUtils.inject() + AndroidLoggingHandler.inject() + AndroidStreamChannelFactory.inject() + + AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) + + AndroidThreeTenBackport.init(app) + } + + override fun onPostInit() = Unit + + override fun onAttachBaseContext() { + if (BuildConfig.DEBUG) { + MultiDex.install(app) + } + } +} diff --git a/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt b/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt index 5aea5d0f7..bfb5be46c 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/app/QuasseldroidReleaseDelegate.kt @@ -21,8 +21,6 @@ package de.kuschku.quasseldroid.app import android.os.Build import android.os.StrictMode -import androidx.appcompat.app.AppCompatDelegate -import androidx.multidex.MultiDex import com.squareup.leakcanary.LeakCanary import de.kuschku.malheur.CrashHandler import de.kuschku.quasseldroid.BuildConfig @@ -34,45 +32,26 @@ import de.kuschku.quasseldroid.persistence.models.Account import de.kuschku.quasseldroid.settings.AppearanceSettings import de.kuschku.quasseldroid.settings.SettingsMigration import de.kuschku.quasseldroid.settings.SettingsMigrationManager -import de.kuschku.quasseldroid.util.backport.AndroidThreeTenBackport -import de.kuschku.quasseldroid.util.compatibility.AndroidCompatibilityUtils -import de.kuschku.quasseldroid.util.compatibility.AndroidLoggingHandler -import de.kuschku.quasseldroid.util.compatibility.AndroidStreamChannelFactory -class QuasseldroidReleaseDelegate(private val app: Quasseldroid) : - AppDelegate { +class QuasseldroidReleaseDelegate(private val app: Quasseldroid) : QuasseldroidBaseDelegate(app) { override fun shouldInit() = !LeakCanary.isInAnalyzerProcess(app) - override fun onInit() { + override fun onPreInit() { LeakCanary.install(app) - // Normal app init code... - CrashHandler.init<BuildConfig>(application = app) - - // Init compatibility utils - AndroidCompatibilityUtils.inject() - AndroidLoggingHandler.inject() - AndroidStreamChannelFactory.inject() - - AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) - - AndroidThreeTenBackport.init(app) } override fun onPostInit() { // Migrate preferences SettingsMigrationManager( listOf( - SettingsMigration.migrationOf(0, - 1) { prefs, edit -> + SettingsMigration.migrationOf(0, 1) { prefs, edit -> // Migrating database - val database = LegacyAccountDatabase.Creator.init( - app) + val database = LegacyAccountDatabase.Creator.init(app) val accounts = database.accounts().all() database.close() - val accountDatabase = AccountDatabase.Creator.init( - app) + val accountDatabase = AccountDatabase.Creator.init(app) accountDatabase.accounts().create(*accounts.map { Account( id = it.id, @@ -205,10 +184,4 @@ class QuasseldroidReleaseDelegate(private val app: Quasseldroid) : ) } } - - override fun onInstallMultidex() { - if (BuildConfig.DEBUG) { - MultiDex.install(app) - } - } } diff --git a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountAdapter.kt b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountAdapter.kt index dc922c52d..590ff921a 100644 --- a/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountAdapter.kt +++ b/app/src/main/java/de/kuschku/quasseldroid/ui/setup/accounts/selection/AccountAdapter.kt @@ -194,6 +194,8 @@ class AccountAdapter( } sealed class AccountViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + internal var data: Account? = null + class Item(itemView: View, actionListener: ItemListener, clickListener: ItemListener) : AccountViewHolder(itemView) { @BindView(R.id.account_name) @@ -208,20 +210,18 @@ class AccountAdapter( @BindView(R.id.account_edit) lateinit var accountEdit: AppCompatImageButton - private var id = -1L - init { ButterKnife.bind(this, itemView) accountEdit.setOnClickListener { - actionListener.onAction(id, adapterPosition) + actionListener.onAction(data?.id ?: -1L, adapterPosition) } itemView.setOnClickListener { - clickListener.onAction(id, adapterPosition) + clickListener.onAction(data?.id ?: -1L, adapterPosition) } } fun bind(account: Account, selected: Boolean) { - id = account.id + data = account accountName.text = account.name accountDescription.text = itemView.context.resources.getString( R.string.label_user_on_host, account.user, account.host, account.port @@ -230,7 +230,7 @@ class AccountAdapter( } fun clear() { - id = -1L + data = null accountName.text = "" accountDescription.text = "" accountSelect.isChecked = false diff --git a/app/src/test/java/de/kuschku/quasseldroid/app/QuasseldroidTestDelegate.kt b/app/src/test/java/de/kuschku/quasseldroid/app/QuasseldroidTestDelegate.kt index 2341e01b8..541751f17 100644 --- a/app/src/test/java/de/kuschku/quasseldroid/app/QuasseldroidTestDelegate.kt +++ b/app/src/test/java/de/kuschku/quasseldroid/app/QuasseldroidTestDelegate.kt @@ -21,7 +21,8 @@ package de.kuschku.quasseldroid.app class QuasseldroidTestDelegate : AppDelegate { override fun shouldInit() = true - override fun onInstallMultidex() = Unit + override fun onAttachBaseContext() = Unit + override fun onPreInit() = Unit override fun onInit() = Unit override fun onPostInit() = Unit } -- GitLab