mirror of
https://github.com/nextcloud/android.git
synced 2024-11-23 05:35:39 +03:00
commit
bc0b9e78f1
25 changed files with 992 additions and 1 deletions
|
@ -257,6 +257,7 @@ dependencies {
|
|||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.0.0'
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.0.0"
|
||||
implementation 'com.github.albfernandez:juniversalchardet:2.0.3' // need this version for Android <7
|
||||
implementation 'com.google.code.findbugs:annotations:2.0.1'
|
||||
implementation 'commons-io:commons-io:2.6'
|
||||
|
@ -306,6 +307,7 @@ dependencies {
|
|||
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
|
||||
testImplementation 'org.json:json:20180813'
|
||||
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
|
||||
testImplementation "androidx.arch.core:core-testing:2.0.1"
|
||||
|
||||
// dependencies for instrumented tests
|
||||
// JUnit4 Rules
|
||||
|
|
|
@ -386,6 +386,10 @@
|
|||
android:name=".ui.activity.SsoGrantPermissionActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.ownCloud.Dialog.NoTitle" />
|
||||
|
||||
<activity
|
||||
android:name="com.nextcloud.client.etm.EtmActivity"
|
||||
android:theme="@style/Theme.ownCloud.Toolbar"/>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -42,10 +42,12 @@ import dagger.android.support.AndroidSupportInjectionModule;
|
|||
AppInfoModule.class,
|
||||
NetworkModule.class,
|
||||
DeviceModule.class,
|
||||
OnboardingModule.class
|
||||
OnboardingModule.class,
|
||||
ViewModelModule.class
|
||||
})
|
||||
@Singleton
|
||||
public interface AppComponent {
|
||||
|
||||
void inject(MainApp app);
|
||||
|
||||
@Component.Builder
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
package com.nextcloud.client.di;
|
||||
|
||||
import com.nextcloud.client.onboarding.FirstRunActivity;
|
||||
import com.nextcloud.client.etm.EtmActivity;
|
||||
import com.nextcloud.client.onboarding.WhatsNewActivity;
|
||||
import com.owncloud.android.authentication.AuthenticatorActivity;
|
||||
import com.owncloud.android.authentication.DeepLinkLoginActivity;
|
||||
|
@ -121,6 +122,7 @@ abstract class ComponentsModule {
|
|||
@ContributesAndroidInjector abstract UploadPathActivity uploadPathActivity();
|
||||
@ContributesAndroidInjector abstract UserInfoActivity userInfoActivity();
|
||||
@ContributesAndroidInjector abstract WhatsNewActivity whatsNewActivity();
|
||||
@ContributesAndroidInjector abstract EtmActivity etmActivity();
|
||||
|
||||
@ContributesAndroidInjector abstract ExtendedListFragment extendedListFragment();
|
||||
@ContributesAndroidInjector abstract FileDetailFragment fileDetailFragment();
|
||||
|
|
64
src/main/java/com/nextcloud/client/di/ViewModelFactory.kt
Normal file
64
src/main/java/com/nextcloud/client/di/ViewModelFactory.kt
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.di
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
||||
/**
|
||||
* This factory provide [ViewModel] instances initialized by Dagger 2 dependency injection system.
|
||||
*
|
||||
* Each [javax.inject.Provider] instance accesses Dagger machinery, which provide
|
||||
* fully-initialized [ViewModel] instance.
|
||||
*
|
||||
* @see ViewModelModule
|
||||
* @see ViewModelKey
|
||||
*/
|
||||
class ViewModelFactory @Inject constructor(
|
||||
private val viewModelProviders: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
|
||||
) : ViewModelProvider.Factory {
|
||||
|
||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
||||
var vmProvider: Provider<ViewModel>? = viewModelProviders.get(modelClass)
|
||||
|
||||
if (vmProvider == null) {
|
||||
for (entry in viewModelProviders.entries) {
|
||||
if (modelClass.isAssignableFrom(entry.key)) {
|
||||
vmProvider = entry.value
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vmProvider == null) {
|
||||
throw IllegalArgumentException("${modelClass.simpleName} view model class is not supported")
|
||||
}
|
||||
|
||||
@Suppress("TooGenericExceptionCaught", "TooGenericExceptionThrown", "UNCHECKED_CAST")
|
||||
try {
|
||||
val vm = vmProvider.get() as T
|
||||
return vm
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
}
|
30
src/main/java/com/nextcloud/client/di/ViewModelKey.kt
Normal file
30
src/main/java/com/nextcloud/client/di/ViewModelKey.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.di
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import dagger.MapKey
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@MustBeDocumented
|
||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@MapKey
|
||||
annotation class ViewModelKey(val value: KClass<out ViewModel>)
|
38
src/main/java/com/nextcloud/client/di/ViewModelModule.kt
Normal file
38
src/main/java/com/nextcloud/client/di/ViewModelModule.kt
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.di
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.nextcloud.client.etm.EtmViewModel
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.IntoMap
|
||||
|
||||
@Module
|
||||
abstract class ViewModelModule {
|
||||
@Binds
|
||||
@IntoMap
|
||||
@ViewModelKey(EtmViewModel::class)
|
||||
abstract fun etmViewModel(vm: EtmViewModel): ViewModel
|
||||
|
||||
@Binds
|
||||
abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
|
||||
}
|
91
src/main/java/com/nextcloud/client/etm/EtmActivity.kt
Normal file
91
src/main/java/com/nextcloud/client/etm/EtmActivity.kt
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.etm
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.nextcloud.client.di.Injectable
|
||||
import com.nextcloud.client.di.ViewModelFactory
|
||||
import com.owncloud.android.R
|
||||
import com.owncloud.android.ui.activity.ToolbarActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
class EtmActivity : ToolbarActivity(), Injectable {
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun launch(context: Context) {
|
||||
val etmIntent = Intent(context, EtmActivity::class.java)
|
||||
context.startActivity(etmIntent)
|
||||
}
|
||||
}
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelFactory
|
||||
internal lateinit var vm: EtmViewModel
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_etm)
|
||||
setupToolbar()
|
||||
updateActionBarTitleAndHomeButtonByString(getString(R.string.etm_title))
|
||||
vm = ViewModelProvider(this, viewModelFactory).get(EtmViewModel::class.java)
|
||||
vm.currentPage.observe(this, Observer {
|
||||
onPageChanged(it)
|
||||
})
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
return when (item?.itemId) {
|
||||
android.R.id.home -> {
|
||||
if (!vm.onBackPressed()) {
|
||||
finish()
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (!vm.onBackPressed()) {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onPageChanged(page: EtmMenuEntry?) {
|
||||
if (page != null) {
|
||||
val fragment = page.pageClass.java.getConstructor().newInstance()
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.etm_page_container, fragment)
|
||||
.commit()
|
||||
updateActionBarTitleAndHomeButtonByString("ETM - ${getString(page.titleRes)}")
|
||||
} else {
|
||||
supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.etm_page_container, EtmMenuFragment())
|
||||
.commitNow()
|
||||
updateActionBarTitleAndHomeButtonByString(getString(R.string.etm_title))
|
||||
}
|
||||
}
|
||||
}
|
28
src/main/java/com/nextcloud/client/etm/EtmBaseFragment.kt
Normal file
28
src/main/java/com/nextcloud/client/etm/EtmBaseFragment.kt
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.etm
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
|
||||
abstract class EtmBaseFragment : Fragment() {
|
||||
protected val vm: EtmViewModel get() {
|
||||
return (activity as EtmActivity).vm
|
||||
}
|
||||
}
|
68
src/main/java/com/nextcloud/client/etm/EtmMenuAdapter.kt
Normal file
68
src/main/java/com/nextcloud/client/etm/EtmMenuAdapter.kt
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.etm
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.owncloud.android.R
|
||||
|
||||
class EtmMenuAdapter(
|
||||
context: Context,
|
||||
val onItemClicked: (Int) -> Unit
|
||||
) : RecyclerView.Adapter<EtmMenuAdapter.PageViewHolder>() {
|
||||
|
||||
private val layoutInflater = LayoutInflater.from(context)
|
||||
var pages: List<EtmMenuEntry> = listOf()
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
class PageViewHolder(view: View, onClick: (Int) -> Unit) : RecyclerView.ViewHolder(view) {
|
||||
val primaryAction: ImageView = view.findViewById(R.id.primary_action)
|
||||
val text: TextView = view.findViewById(R.id.text)
|
||||
val secondaryAction: ImageView = view.findViewById(R.id.secondary_action)
|
||||
|
||||
init {
|
||||
itemView.setOnClickListener { onClick(adapterPosition) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PageViewHolder {
|
||||
val view = layoutInflater.inflate(R.layout.material_list_item_single_line, parent, false)
|
||||
return PageViewHolder(view, onItemClicked)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PageViewHolder, position: Int) {
|
||||
val page = pages[position]
|
||||
holder.primaryAction.setImageResource(page.iconRes)
|
||||
holder.text.setText(page.titleRes)
|
||||
holder.secondaryAction.setImageResource(0)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return pages.size
|
||||
}
|
||||
}
|
25
src/main/java/com/nextcloud/client/etm/EtmMenuEntry.kt
Normal file
25
src/main/java/com/nextcloud/client/etm/EtmMenuEntry.kt
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.etm
|
||||
|
||||
import androidx.fragment.app.Fragment
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
data class EtmMenuEntry(val iconRes: Int, val titleRes: Int, val pageClass: KClass<out Fragment>)
|
53
src/main/java/com/nextcloud/client/etm/EtmMenuFragment.kt
Normal file
53
src/main/java/com/nextcloud/client/etm/EtmMenuFragment.kt
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.etm
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.owncloud.android.R
|
||||
|
||||
class EtmMenuFragment : EtmBaseFragment() {
|
||||
|
||||
private lateinit var adapter: EtmMenuAdapter
|
||||
private lateinit var list: RecyclerView
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
adapter = EtmMenuAdapter(context!!, this::onClickedItem)
|
||||
adapter.pages = vm.pages
|
||||
val view = inflater.inflate(R.layout.fragment_etm_menu, container, false)
|
||||
list = view.findViewById(R.id.etm_menu_list)
|
||||
list.layoutManager = LinearLayoutManager(context!!)
|
||||
list.adapter = adapter
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
activity?.setTitle(R.string.etm_title)
|
||||
}
|
||||
|
||||
private fun onClickedItem(position: Int) {
|
||||
vm.onPageSelected(position)
|
||||
}
|
||||
}
|
71
src/main/java/com/nextcloud/client/etm/EtmViewModel.kt
Normal file
71
src/main/java/com/nextcloud/client/etm/EtmViewModel.kt
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.etm
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.nextcloud.client.etm.pages.EtmPreferencesFragment
|
||||
import com.owncloud.android.R
|
||||
import javax.inject.Inject
|
||||
|
||||
class EtmViewModel @Inject constructor(
|
||||
private val defaultPreferences: SharedPreferences
|
||||
) : ViewModel() {
|
||||
val currentPage: LiveData<EtmMenuEntry?> = MutableLiveData()
|
||||
val pages: List<EtmMenuEntry> = listOf(
|
||||
EtmMenuEntry(
|
||||
iconRes = R.drawable.ic_settings,
|
||||
titleRes = R.string.etm_preferences,
|
||||
pageClass = EtmPreferencesFragment::class
|
||||
)
|
||||
)
|
||||
|
||||
val preferences: Map<String, String> get() {
|
||||
return defaultPreferences.all
|
||||
.map { it.key to "${it.value}" }
|
||||
.sortedBy { it.first }
|
||||
.toMap()
|
||||
}
|
||||
|
||||
init {
|
||||
(currentPage as MutableLiveData).apply {
|
||||
value = null
|
||||
}
|
||||
}
|
||||
|
||||
fun onPageSelected(index: Int) {
|
||||
if (index < pages.size) {
|
||||
currentPage as MutableLiveData
|
||||
currentPage.value = pages[index]
|
||||
}
|
||||
}
|
||||
|
||||
fun onBackPressed(): Boolean {
|
||||
(currentPage as MutableLiveData)
|
||||
return if (currentPage.value != null) {
|
||||
currentPage.value = null
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.etm.pages
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.nextcloud.client.etm.EtmBaseFragment
|
||||
import com.owncloud.android.R
|
||||
import kotlinx.android.synthetic.main.fragment_etm_preferences.*
|
||||
|
||||
class EtmPreferencesFragment : EtmBaseFragment() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.fragment_etm_preferences, container, false)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val builder = StringBuilder()
|
||||
vm.preferences.forEach { builder.append("${it.key}: ${it.value}\n") }
|
||||
etm_preferences_text.text = builder
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
|
||||
super.onCreateOptionsMenu(menu, inflater)
|
||||
inflater?.inflate(R.menu.etm_preferences, menu)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
||||
return when (item?.itemId) {
|
||||
R.id.etm_preferences_share -> {
|
||||
onClickedShare(); true
|
||||
}
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onClickedShare() {
|
||||
val intent = Intent(Intent.ACTION_SEND)
|
||||
intent.putExtra(Intent.EXTRA_SUBJECT, "Nextcloud preferences")
|
||||
intent.putExtra(Intent.EXTRA_TEXT, etm_preferences_text.text)
|
||||
intent.type = "text/plain"
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@ import com.nextcloud.client.account.UserAccountManager;
|
|||
import com.nextcloud.client.appinfo.AppInfo;
|
||||
import com.nextcloud.client.device.PowerManagementService;
|
||||
import com.nextcloud.client.di.ActivityInjector;
|
||||
import com.nextcloud.client.di.AppComponent;
|
||||
import com.nextcloud.client.di.DaggerAppComponent;
|
||||
import com.nextcloud.client.network.ConnectivityService;
|
||||
import com.nextcloud.client.onboarding.OnboardingService;
|
||||
|
|
|
@ -55,6 +55,7 @@ import android.webkit.URLUtil;
|
|||
|
||||
import com.nextcloud.client.account.UserAccountManager;
|
||||
import com.nextcloud.client.di.Injectable;
|
||||
import com.nextcloud.client.etm.EtmActivity;
|
||||
import com.nextcloud.client.preferences.AppPreferences;
|
||||
import com.nextcloud.client.preferences.AppPreferencesImpl;
|
||||
import com.owncloud.android.BuildConfig;
|
||||
|
@ -207,6 +208,15 @@ public class SettingsActivity extends PreferenceActivity
|
|||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/* Engineering Test Mode */
|
||||
Preference pEtm = findPreference("etm");
|
||||
if (pEtm != null) {
|
||||
pEtm.setOnPreferenceClickListener(preference -> {
|
||||
EtmActivity.launch(this);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
preferenceScreen.removePreference(preferenceCategoryDev);
|
||||
}
|
||||
|
|
39
src/main/res/layout/activity_etm.xml
Normal file
39
src/main/res/layout/activity_etm.xml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
@author Chris Narkiewicz
|
||||
Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".etm.EtmActivity">
|
||||
|
||||
<include layout="@layout/toolbar_standard"/>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:id="@+id/etm_page_container">
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
32
src/main/res/layout/fragment_etm_menu.xml
Normal file
32
src/main/res/layout/fragment_etm_menu.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
@author Chris Narkiewicz
|
||||
Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.nextcloud.client.etm.EtmMenuFragment">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/etm_menu_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
</FrameLayout>
|
33
src/main/res/layout/fragment_etm_preferences.xml
Normal file
33
src/main/res/layout/fragment_etm_preferences.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
@author Chris Narkiewicz
|
||||
Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.nextcloud.client.etm.pages.EtmPreferencesFragment">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/etm_preferences_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="@dimen/standard_padding"
|
||||
android:scrollbars="vertical"/>
|
||||
|
||||
</FrameLayout>
|
51
src/main/res/layout/material_list_item_single_line.xml
Normal file
51
src/main/res/layout/material_list_item_single_line.xml
Normal file
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
@author Chris Narkiewicz
|
||||
Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<!--
|
||||
This is a generic, single row list item matching Material Design specification.
|
||||
-->
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
style="@style/MaterialListItemSingleLine">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
style="@style/MaterialListItemPrimaryAction"
|
||||
android:id="@+id/primary_action"
|
||||
tools:src="@drawable/ic_alert"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_width="0dip"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp"
|
||||
android:lines="1"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
tools:text="Single line of text"/>
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
style="@style/MaterialListItemSecondaryAction"
|
||||
android:id="@+id/secondary_action"
|
||||
tools:src="@drawable/ic_alert"/>
|
||||
|
||||
</LinearLayout>
|
33
src/main/res/menu/etm_preferences.xml
Normal file
33
src/main/res/menu/etm_preferences.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
@author Chris Narkiewicz
|
||||
Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:ignore="AppCompatResource">
|
||||
|
||||
<item
|
||||
android:id="@+id/etm_preferences_share"
|
||||
android:title="@string/etm_share"
|
||||
app:showAsAction="ifRoom"
|
||||
android:showAsAction="ifRoom"
|
||||
android:icon="@drawable/ic_share" />
|
||||
|
||||
</menu>
|
|
@ -872,4 +872,8 @@
|
|||
<string name="copy_internal_link">Copy internal link</string>
|
||||
<string name="copy_internal_link_subline">Only works for users with access to this folder</string>
|
||||
<string name="failed_to_download">Failed to pass file to download manager</string>
|
||||
|
||||
<string name="etm_title">Engineering Test Mode</string>
|
||||
<string name="etm_preferences">Preferences</string>
|
||||
<string name="etm_share">Share</string>
|
||||
</resources>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
Copyright (C) 2012 Bartek Przybylski
|
||||
Copyright (C) 2015 ownCloud Inc.
|
||||
Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2,
|
||||
|
@ -284,4 +285,33 @@
|
|||
<item name="android:textSize">16sp</item>
|
||||
<item name="textAllCaps">false</item>
|
||||
</style>
|
||||
|
||||
<style name="MaterialListItemSingleLine">
|
||||
<item name="android:clickable">true</item>
|
||||
<item name="android:background">?android:selectableItemBackground</item>
|
||||
<item name="android:paddingLeft">16dp</item>
|
||||
<item name="android:paddingRight">16dp</item>
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="MaterialListItemPrimaryAction">
|
||||
<item name="tint">?android:attr/textColorSecondary</item>
|
||||
<item name="android:layout_width">32dp</item>
|
||||
<item name="android:layout_height">32dp</item>
|
||||
<item name="android:layout_marginRight">16dp</item>
|
||||
<item name="android:scaleType">fitCenter</item>
|
||||
<item name="android:layout_gravity">center_vertical</item>
|
||||
</style>
|
||||
|
||||
<style name="MaterialListItemSecondaryAction">
|
||||
<item name="tint">?android:attr/textColorSecondary</item>
|
||||
<item name="android:layout_width">24dp</item>
|
||||
<item name="android:layout_height">24dp</item>
|
||||
<item name="android:layout_marginLeft">16dp</item>
|
||||
<item name="android:scaleType">fitCenter</item>
|
||||
<item name="android:layout_gravity">center_vertical</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
Copyright (C) 2012 Bartek Przybylski
|
||||
Copyright (C) 2012-2013 ownCloud Inc.
|
||||
Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2,
|
||||
|
@ -95,6 +96,10 @@
|
|||
<Preference android:id="@+id/changelog_link"
|
||||
android:title="Changelog dev version"
|
||||
android:key="changelog_link" />
|
||||
|
||||
<Preference android:id="@+id/etm"
|
||||
android:title="@string/etm_title"
|
||||
android:key="etm" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
202
src/test/java/com/nextcloud/client/etm/TestEtmViewModel.kt
Normal file
202
src/test/java/com/nextcloud/client/etm/TestEtmViewModel.kt
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Chris Narkiewicz
|
||||
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.client.etm
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.lifecycle.Observer
|
||||
import com.nhaarman.mockitokotlin2.anyOrNull
|
||||
import com.nhaarman.mockitokotlin2.eq
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.never
|
||||
import com.nhaarman.mockitokotlin2.reset
|
||||
import com.nhaarman.mockitokotlin2.same
|
||||
import com.nhaarman.mockitokotlin2.times
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Suite
|
||||
|
||||
@RunWith(Suite::class)
|
||||
@Suite.SuiteClasses(
|
||||
TestEtmViewModel.MainPage::class,
|
||||
TestEtmViewModel.PreferencesPage::class
|
||||
)
|
||||
class TestEtmViewModel {
|
||||
|
||||
internal abstract class Base {
|
||||
|
||||
@get:Rule
|
||||
val rule = InstantTaskExecutorRule()
|
||||
|
||||
protected lateinit var sharedPreferences: SharedPreferences
|
||||
protected lateinit var vm: EtmViewModel
|
||||
|
||||
@Before
|
||||
fun setUpBase() {
|
||||
sharedPreferences = mock()
|
||||
vm = EtmViewModel(sharedPreferences)
|
||||
}
|
||||
}
|
||||
|
||||
internal class MainPage : Base() {
|
||||
|
||||
@Test
|
||||
fun `current page is not set`() {
|
||||
// GIVEN
|
||||
// main page is displayed
|
||||
// THEN
|
||||
// current page is null
|
||||
assertNull(vm.currentPage.value)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `back key is not handled`() {
|
||||
// GIVEN
|
||||
// main page is displayed
|
||||
// WHEN
|
||||
// back key is pressed
|
||||
val handled = vm.onBackPressed()
|
||||
|
||||
// THEN
|
||||
// is not handled
|
||||
assertFalse(handled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `page is selected`() {
|
||||
val observer: Observer<EtmMenuEntry?> = mock()
|
||||
val selectedPageIndex = 0
|
||||
val expectedPage = vm.pages[selectedPageIndex]
|
||||
|
||||
// GIVEN
|
||||
// main page is displayed
|
||||
// current page observer is registered
|
||||
vm.currentPage.observeForever(observer)
|
||||
reset(observer)
|
||||
|
||||
// WHEN
|
||||
// page is selected
|
||||
vm.onPageSelected(selectedPageIndex)
|
||||
|
||||
// THEN
|
||||
// current page is set
|
||||
// page observer is called once with selected entry
|
||||
assertNotNull(vm.currentPage.value)
|
||||
verify(observer, times(1)).onChanged(same(expectedPage))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `out of range index is ignored`() {
|
||||
val maxIndex = vm.pages.size
|
||||
// GIVEN
|
||||
// observer is registered
|
||||
val observer: Observer<EtmMenuEntry?> = mock()
|
||||
vm.currentPage.observeForever(observer)
|
||||
reset(observer)
|
||||
|
||||
// WHEN
|
||||
// out of range page index is selected
|
||||
vm.onPageSelected(maxIndex + 1)
|
||||
|
||||
// THEN
|
||||
// nothing happens
|
||||
verify(observer, never()).onChanged(anyOrNull())
|
||||
assertNull(vm.currentPage.value)
|
||||
}
|
||||
}
|
||||
|
||||
internal class PreferencesPage : Base() {
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
vm.onPageSelected(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `back goes back to main page`() {
|
||||
val observer: Observer<EtmMenuEntry?> = mock()
|
||||
|
||||
// GIVEN
|
||||
// a page is selected
|
||||
// page observer is registered
|
||||
assertNotNull(vm.currentPage.value)
|
||||
vm.currentPage.observeForever(observer)
|
||||
|
||||
// WHEN
|
||||
// back is pressed
|
||||
val handled = vm.onBackPressed()
|
||||
|
||||
// THEN
|
||||
// back press is handled
|
||||
// observer is called with null page
|
||||
assertTrue(handled)
|
||||
verify(observer).onChanged(eq(null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `back is handled only once`() {
|
||||
// GIVEN
|
||||
// a page is selected
|
||||
assertNotNull(vm.currentPage.value)
|
||||
|
||||
// WHEN
|
||||
// back is pressed twice
|
||||
val first = vm.onBackPressed()
|
||||
val second = vm.onBackPressed()
|
||||
|
||||
// THEN
|
||||
// back is handled only once
|
||||
assertTrue(first)
|
||||
assertFalse(second)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `preferences are loaded from shared preferences`() {
|
||||
// GIVEN
|
||||
// shared preferences contain values of different types
|
||||
val preferenceValues: Map<String, Any> = mapOf(
|
||||
"key1" to 1,
|
||||
"key2" to "value2",
|
||||
"key3" to false
|
||||
)
|
||||
whenever(sharedPreferences.all).thenReturn(preferenceValues)
|
||||
|
||||
// WHEN
|
||||
// vm preferences are read
|
||||
val prefs = vm.preferences
|
||||
|
||||
// THEN
|
||||
// all preferences are converted to strings
|
||||
assertEquals(preferenceValues.size, prefs.size)
|
||||
assertEquals("1", prefs["key1"])
|
||||
assertEquals("value2", prefs["key2"])
|
||||
assertEquals("false", prefs["key3"])
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue