123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- /*
- * Nextcloud Android client application
- *
- * @author Bartosz Przybylski
- * @author Chris Narkiewicz
- * Copyright (C) 2015 Bartosz Przybylski
- * Copyright (C) 2015 ownCloud Inc.
- * Copyright (C) 2016 Nextcloud.
- * 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
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or 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.onboarding
- import android.accounts.AccountManager
- import android.content.Intent
- import android.content.res.Configuration
- import android.os.Bundle
- import android.view.View
- import android.view.ViewGroup
- import android.widget.LinearLayout
- import androidx.activity.OnBackPressedCallback
- import androidx.activity.result.ActivityResult
- import androidx.activity.result.ActivityResultLauncher
- import androidx.activity.result.contract.ActivityResultContracts
- import androidx.viewpager.widget.ViewPager
- import com.nextcloud.android.common.ui.theme.utils.ColorRole
- import com.nextcloud.client.account.UserAccountManager
- import com.nextcloud.client.appinfo.AppInfo
- import com.nextcloud.client.di.Injectable
- import com.nextcloud.client.preferences.AppPreferences
- import com.owncloud.android.BuildConfig
- import com.owncloud.android.R
- import com.owncloud.android.authentication.AuthenticatorActivity
- import com.owncloud.android.databinding.FirstRunActivityBinding
- import com.owncloud.android.features.FeatureItem
- import com.owncloud.android.ui.activity.BaseActivity
- import com.owncloud.android.ui.activity.FileDisplayActivity
- import com.owncloud.android.ui.adapter.FeaturesViewAdapter
- import com.owncloud.android.utils.DisplayUtils
- import com.owncloud.android.utils.theme.ViewThemeUtils
- import javax.inject.Inject
- /**
- * Activity displaying general feature after a fresh install.
- */
- class FirstRunActivity : BaseActivity(), ViewPager.OnPageChangeListener, Injectable {
- @JvmField
- @Inject
- var userAccountManager: UserAccountManager? = null
- @JvmField
- @Inject
- var preferences: AppPreferences? = null
- @JvmField
- @Inject
- var appInfo: AppInfo? = null
- @JvmField
- @Inject
- var onboarding: OnboardingService? = null
- @JvmField
- @Inject
- var viewThemeUtilsFactory: ViewThemeUtils.Factory? = null
- private var activityResult: ActivityResultLauncher<Intent>? = null
- private lateinit var binding: FirstRunActivityBinding
- private var defaultViewThemeUtils: ViewThemeUtils? = null
- override fun onCreate(savedInstanceState: Bundle?) {
- enableAccountHandling = false
- super.onCreate(savedInstanceState)
- applyDefaultTheme()
- binding = FirstRunActivityBinding.inflate(layoutInflater)
- setContentView(binding.root)
- val isProviderOrOwnInstallationVisible = resources.getBoolean(R.bool.show_provider_or_own_installation)
- setSlideshowSize(resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE)
- registerActivityResult()
- setupLoginButton()
- setupSignupButton(isProviderOrOwnInstallationVisible)
- setupHostOwnServerTextView(isProviderOrOwnInstallationVisible)
- deleteAccountAtFirstLaunch()
- setupFeaturesViewAdapter()
- handleOnBackPressed()
- }
- private fun applyDefaultTheme() {
- defaultViewThemeUtils = viewThemeUtilsFactory?.withPrimaryAsBackground()
- defaultViewThemeUtils?.platform?.themeStatusBar(this, ColorRole.PRIMARY)
- }
- private fun registerActivityResult() {
- activityResult =
- registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
- if (RESULT_OK == result.resultCode) {
- val data = result.data
- val accountName = data?.getStringExtra(AccountManager.KEY_ACCOUNT_NAME)
- val account = userAccountManager?.getAccountByName(accountName)
- if (account == null) {
- DisplayUtils.showSnackMessage(this, R.string.account_creation_failed)
- return@registerForActivityResult
- }
- userAccountManager?.setCurrentOwnCloudAccount(account.name)
- val i = Intent(this, FileDisplayActivity::class.java)
- i.action = FileDisplayActivity.RESTART
- i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
- startActivity(i)
- finish()
- }
- }
- }
- private fun setupLoginButton() {
- defaultViewThemeUtils?.material?.colorMaterialButtonFilledOnPrimary(binding.login)
- binding.login.setOnClickListener {
- if (intent.getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
- val authenticatorActivityIntent = getAuthenticatorActivityIntent(false)
- activityResult?.launch(authenticatorActivityIntent)
- } else {
- finish()
- }
- }
- }
- private fun setupSignupButton(isProviderOrOwnInstallationVisible: Boolean) {
- defaultViewThemeUtils?.material?.colorMaterialButtonOutlinedOnPrimary(binding.signup)
- binding.signup.visibility = if (isProviderOrOwnInstallationVisible) View.VISIBLE else View.GONE
- binding.signup.setOnClickListener {
- val authenticatorActivityIntent = getAuthenticatorActivityIntent(true)
- if (intent.getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
- activityResult?.launch(authenticatorActivityIntent)
- } else {
- authenticatorActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- startActivity(authenticatorActivityIntent)
- }
- }
- }
- private fun getAuthenticatorActivityIntent(extraUseProviderAsWebLogin: Boolean): Intent {
- val intent = Intent(this, AuthenticatorActivity::class.java)
- intent.putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, extraUseProviderAsWebLogin)
- return intent
- }
- private fun setupHostOwnServerTextView(isProviderOrOwnInstallationVisible: Boolean) {
- defaultViewThemeUtils?.platform?.colorTextView(binding.hostOwnServer, ColorRole.ON_PRIMARY)
- binding.hostOwnServer.visibility = if (isProviderOrOwnInstallationVisible) View.VISIBLE else View.GONE
- if (isProviderOrOwnInstallationVisible) {
- binding.hostOwnServer.setOnClickListener {
- DisplayUtils.startLinkIntent(
- this,
- R.string.url_server_install
- )
- }
- }
- }
- // Sometimes, accounts are not deleted when you uninstall the application so we'll do it now
- private fun deleteAccountAtFirstLaunch() {
- if (onboarding?.isFirstRun == true) {
- userAccountManager?.removeAllAccounts()
- }
- }
- @Suppress("SpreadOperator")
- private fun setupFeaturesViewAdapter() {
- val featuresViewAdapter = FeaturesViewAdapter(supportFragmentManager, *firstRun)
- binding.progressIndicator.setNumberOfSteps(featuresViewAdapter.count)
- binding.contentPanel.adapter = featuresViewAdapter
- binding.contentPanel.addOnPageChangeListener(this)
- }
- private fun handleOnBackPressed() {
- onBackPressedDispatcher.addCallback(
- this,
- object : OnBackPressedCallback(true) {
- override fun handleOnBackPressed() {
- onFinish()
- if (intent.getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
- onBackPressedDispatcher.onBackPressed()
- } else {
- val intent = Intent(applicationContext, AuthenticatorActivity::class.java)
- intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
- intent.putExtra(EXTRA_EXIT, true)
- startActivity(intent)
- finish()
- }
- }
- }
- )
- }
- private fun setSlideshowSize(isLandscape: Boolean) {
- val isProviderOrOwnInstallationVisible = resources.getBoolean(R.bool.show_provider_or_own_installation)
- binding.buttonLayout.orientation = if (isLandscape) LinearLayout.HORIZONTAL else LinearLayout.VERTICAL
- val layoutParams: LinearLayout.LayoutParams = if (isProviderOrOwnInstallationVisible) {
- LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- } else {
- @Suppress("MagicNumber")
- LinearLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- DisplayUtils.convertDpToPixel(if (isLandscape) 100f else 150f, this)
- )
- }
- binding.bottomLayout.layoutParams = layoutParams
- }
- override fun onConfigurationChanged(newConfig: Configuration) {
- super.onConfigurationChanged(newConfig)
- setSlideshowSize(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
- }
- private fun onFinish() {
- preferences?.lastSeenVersionCode = BuildConfig.VERSION_CODE
- }
- override fun onStop() {
- onFinish()
- super.onStop()
- }
- override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
- // unused but to be implemented due to abstract parent
- }
- override fun onPageSelected(position: Int) {
- binding.progressIndicator.animateToStep(position + 1)
- }
- override fun onPageScrollStateChanged(state: Int) {
- // unused but to be implemented due to abstract parent
- }
- companion object {
- const val EXTRA_ALLOW_CLOSE = "ALLOW_CLOSE"
- const val EXTRA_EXIT = "EXIT"
- val firstRun: Array<FeatureItem>
- get() = arrayOf(
- FeatureItem(R.drawable.logo, R.string.first_run_1_text, R.string.empty, true, false),
- FeatureItem(R.drawable.first_run_files, R.string.first_run_2_text, R.string.empty, true, false),
- FeatureItem(R.drawable.first_run_groupware, R.string.first_run_3_text, R.string.empty, true, false),
- FeatureItem(R.drawable.first_run_talk, R.string.first_run_4_text, R.string.empty, true, false)
- )
- }
- }
|