mirror of
https://github.com/nextcloud/android.git
synced 2024-11-26 23:28:42 +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.appcompat:appcompat:1.0.2'
|
||||||
implementation 'androidx.cardview:cardview:1.0.0'
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation 'androidx.exifinterface:exifinterface: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.github.albfernandez:juniversalchardet:2.0.3' // need this version for Android <7
|
||||||
implementation 'com.google.code.findbugs:annotations:2.0.1'
|
implementation 'com.google.code.findbugs:annotations:2.0.1'
|
||||||
implementation 'commons-io:commons-io:2.6'
|
implementation 'commons-io:commons-io:2.6'
|
||||||
|
@ -306,6 +307,7 @@ dependencies {
|
||||||
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
|
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
|
||||||
testImplementation 'org.json:json:20180813'
|
testImplementation 'org.json:json:20180813'
|
||||||
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
|
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.1.0"
|
||||||
|
testImplementation "androidx.arch.core:core-testing:2.0.1"
|
||||||
|
|
||||||
// dependencies for instrumented tests
|
// dependencies for instrumented tests
|
||||||
// JUnit4 Rules
|
// JUnit4 Rules
|
||||||
|
|
|
@ -386,6 +386,10 @@
|
||||||
android:name=".ui.activity.SsoGrantPermissionActivity"
|
android:name=".ui.activity.SsoGrantPermissionActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@style/Theme.ownCloud.Dialog.NoTitle" />
|
android:theme="@style/Theme.ownCloud.Dialog.NoTitle" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="com.nextcloud.client.etm.EtmActivity"
|
||||||
|
android:theme="@style/Theme.ownCloud.Toolbar"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -42,10 +42,12 @@ import dagger.android.support.AndroidSupportInjectionModule;
|
||||||
AppInfoModule.class,
|
AppInfoModule.class,
|
||||||
NetworkModule.class,
|
NetworkModule.class,
|
||||||
DeviceModule.class,
|
DeviceModule.class,
|
||||||
OnboardingModule.class
|
OnboardingModule.class,
|
||||||
|
ViewModelModule.class
|
||||||
})
|
})
|
||||||
@Singleton
|
@Singleton
|
||||||
public interface AppComponent {
|
public interface AppComponent {
|
||||||
|
|
||||||
void inject(MainApp app);
|
void inject(MainApp app);
|
||||||
|
|
||||||
@Component.Builder
|
@Component.Builder
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
package com.nextcloud.client.di;
|
package com.nextcloud.client.di;
|
||||||
|
|
||||||
import com.nextcloud.client.onboarding.FirstRunActivity;
|
import com.nextcloud.client.onboarding.FirstRunActivity;
|
||||||
|
import com.nextcloud.client.etm.EtmActivity;
|
||||||
import com.nextcloud.client.onboarding.WhatsNewActivity;
|
import com.nextcloud.client.onboarding.WhatsNewActivity;
|
||||||
import com.owncloud.android.authentication.AuthenticatorActivity;
|
import com.owncloud.android.authentication.AuthenticatorActivity;
|
||||||
import com.owncloud.android.authentication.DeepLinkLoginActivity;
|
import com.owncloud.android.authentication.DeepLinkLoginActivity;
|
||||||
|
@ -121,6 +122,7 @@ abstract class ComponentsModule {
|
||||||
@ContributesAndroidInjector abstract UploadPathActivity uploadPathActivity();
|
@ContributesAndroidInjector abstract UploadPathActivity uploadPathActivity();
|
||||||
@ContributesAndroidInjector abstract UserInfoActivity userInfoActivity();
|
@ContributesAndroidInjector abstract UserInfoActivity userInfoActivity();
|
||||||
@ContributesAndroidInjector abstract WhatsNewActivity whatsNewActivity();
|
@ContributesAndroidInjector abstract WhatsNewActivity whatsNewActivity();
|
||||||
|
@ContributesAndroidInjector abstract EtmActivity etmActivity();
|
||||||
|
|
||||||
@ContributesAndroidInjector abstract ExtendedListFragment extendedListFragment();
|
@ContributesAndroidInjector abstract ExtendedListFragment extendedListFragment();
|
||||||
@ContributesAndroidInjector abstract FileDetailFragment fileDetailFragment();
|
@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.appinfo.AppInfo;
|
||||||
import com.nextcloud.client.device.PowerManagementService;
|
import com.nextcloud.client.device.PowerManagementService;
|
||||||
import com.nextcloud.client.di.ActivityInjector;
|
import com.nextcloud.client.di.ActivityInjector;
|
||||||
|
import com.nextcloud.client.di.AppComponent;
|
||||||
import com.nextcloud.client.di.DaggerAppComponent;
|
import com.nextcloud.client.di.DaggerAppComponent;
|
||||||
import com.nextcloud.client.network.ConnectivityService;
|
import com.nextcloud.client.network.ConnectivityService;
|
||||||
import com.nextcloud.client.onboarding.OnboardingService;
|
import com.nextcloud.client.onboarding.OnboardingService;
|
||||||
|
|
|
@ -55,6 +55,7 @@ import android.webkit.URLUtil;
|
||||||
|
|
||||||
import com.nextcloud.client.account.UserAccountManager;
|
import com.nextcloud.client.account.UserAccountManager;
|
||||||
import com.nextcloud.client.di.Injectable;
|
import com.nextcloud.client.di.Injectable;
|
||||||
|
import com.nextcloud.client.etm.EtmActivity;
|
||||||
import com.nextcloud.client.preferences.AppPreferences;
|
import com.nextcloud.client.preferences.AppPreferences;
|
||||||
import com.nextcloud.client.preferences.AppPreferencesImpl;
|
import com.nextcloud.client.preferences.AppPreferencesImpl;
|
||||||
import com.owncloud.android.BuildConfig;
|
import com.owncloud.android.BuildConfig;
|
||||||
|
@ -207,6 +208,15 @@ public class SettingsActivity extends PreferenceActivity
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Engineering Test Mode */
|
||||||
|
Preference pEtm = findPreference("etm");
|
||||||
|
if (pEtm != null) {
|
||||||
|
pEtm.setOnPreferenceClickListener(preference -> {
|
||||||
|
EtmActivity.launch(this);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
preferenceScreen.removePreference(preferenceCategoryDev);
|
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">Copy internal link</string>
|
||||||
<string name="copy_internal_link_subline">Only works for users with access to this folder</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="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>
|
</resources>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
Copyright (C) 2012 Bartek Przybylski
|
Copyright (C) 2012 Bartek Przybylski
|
||||||
Copyright (C) 2015 ownCloud Inc.
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License version 2,
|
it under the terms of the GNU General Public License version 2,
|
||||||
|
@ -284,4 +285,33 @@
|
||||||
<item name="android:textSize">16sp</item>
|
<item name="android:textSize">16sp</item>
|
||||||
<item name="textAllCaps">false</item>
|
<item name="textAllCaps">false</item>
|
||||||
</style>
|
</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>
|
</resources>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
Copyright (C) 2012 Bartek Przybylski
|
Copyright (C) 2012 Bartek Przybylski
|
||||||
Copyright (C) 2012-2013 ownCloud Inc.
|
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
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License version 2,
|
it under the terms of the GNU General Public License version 2,
|
||||||
|
@ -95,6 +96,10 @@
|
||||||
<Preference android:id="@+id/changelog_link"
|
<Preference android:id="@+id/changelog_link"
|
||||||
android:title="Changelog dev version"
|
android:title="Changelog dev version"
|
||||||
android:key="changelog_link" />
|
android:key="changelog_link" />
|
||||||
|
|
||||||
|
<Preference android:id="@+id/etm"
|
||||||
|
android:title="@string/etm_title"
|
||||||
|
android:key="etm" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</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