diff --git a/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.java b/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.java deleted file mode 100644 index eb9f06f04e66..000000000000 --- a/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.java +++ /dev/null @@ -1,232 +0,0 @@ -/* - * 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 - * - * 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 . - */ - -package com.nextcloud.client.onboarding; - -import android.accounts.Account; -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 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; - -import androidx.viewpager.widget.ViewPager; - -/** - * Activity displaying general feature after a fresh install. - */ -public class FirstRunActivity extends BaseActivity implements ViewPager.OnPageChangeListener, Injectable { - - public static final String EXTRA_ALLOW_CLOSE = "ALLOW_CLOSE"; - public static final String EXTRA_EXIT = "EXIT"; - public static final int FIRST_RUN_RESULT_CODE = 199; - - @Inject UserAccountManager userAccountManager; - @Inject AppPreferences preferences; - @Inject AppInfo appInfo; - @Inject OnboardingService onboarding; - - @Inject ViewThemeUtils.Factory viewThemeUtilsFactory; - - private FirstRunActivityBinding binding; - private ViewThemeUtils defaultViewThemeUtils; - - @Override - protected void onCreate(Bundle savedInstanceState) { - enableAccountHandling = false; - - super.onCreate(savedInstanceState); - defaultViewThemeUtils = viewThemeUtilsFactory.withPrimaryAsBackground(); - defaultViewThemeUtils.platform.themeStatusBar(this, ColorRole.PRIMARY); - this.binding = FirstRunActivityBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); - - boolean isProviderOrOwnInstallationVisible = getResources().getBoolean(R.bool.show_provider_or_own_installation); - - setSlideshowSize(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE); - - - defaultViewThemeUtils.material.colorMaterialButtonFilledOnPrimary(binding.login); - binding.login.setOnClickListener(v -> { - if (getIntent().getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) { - Intent authenticatorActivityIntent = new Intent(this, AuthenticatorActivity.class); - authenticatorActivityIntent.putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, false); - startActivityForResult(authenticatorActivityIntent, FIRST_RUN_RESULT_CODE); - } else { - finish(); - } - }); - - - defaultViewThemeUtils.material.colorMaterialButtonOutlinedOnPrimary(binding.signup); - binding.signup.setVisibility(isProviderOrOwnInstallationVisible ? View.VISIBLE : View.GONE); - binding.signup.setOnClickListener(v -> { - Intent authenticatorActivityIntent = new Intent(this, AuthenticatorActivity.class); - authenticatorActivityIntent.putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, true); - - if (getIntent().getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) { - startActivityForResult(authenticatorActivityIntent, FIRST_RUN_RESULT_CODE); - } else { - authenticatorActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(authenticatorActivityIntent); - } - }); - - defaultViewThemeUtils.platform.colorTextView(binding.hostOwnServer, ColorRole.ON_PRIMARY); - binding.hostOwnServer.setVisibility(isProviderOrOwnInstallationVisible ? View.VISIBLE : View.GONE); - - if (isProviderOrOwnInstallationVisible) { - binding.hostOwnServer.setOnClickListener(v -> DisplayUtils.startLinkIntent(this, R.string.url_server_install)); - } - - - // Sometimes, accounts are not deleted when you uninstall the application so we'll do it now - if (onboarding.isFirstRun()) { - userAccountManager.removeAllAccounts(); - } - - FeaturesViewAdapter featuresViewAdapter = new FeaturesViewAdapter(getSupportFragmentManager(), getFirstRun()); - binding.progressIndicator.setNumberOfSteps(featuresViewAdapter.getCount()); - binding.contentPanel.setAdapter(featuresViewAdapter); - - binding.contentPanel.addOnPageChangeListener(this); - } - - private void setSlideshowSize(boolean isLandscape) { - boolean isProviderOrOwnInstallationVisible = getResources().getBoolean(R.bool.show_provider_or_own_installation); - - LinearLayout.LayoutParams layoutParams; - - binding.buttonLayout.setOrientation(isLandscape ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); - - if (isProviderOrOwnInstallationVisible) { - layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); - } else { - layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, DisplayUtils.convertDpToPixel(isLandscape ? 100f : 150f, this)); - } - - binding.bottomLayout.setLayoutParams(layoutParams); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - setSlideshowSize(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE); - } - - @Override - public void onBackPressed() { - onFinish(); - - if (getIntent().getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) { - super.onBackPressed(); - } else { - Intent intent = new Intent(getApplicationContext(), AuthenticatorActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(EXTRA_EXIT, true); - startActivity(intent); - finish(); - } - } - - private void onFinish() { - preferences.setLastSeenVersionCode(BuildConfig.VERSION_CODE); - } - - @Override - protected void onStop() { - onFinish(); - - super.onStop(); - } - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - // unused but to be implemented due to abstract parent - } - - @Override - public void onPageSelected(int position) { - binding.progressIndicator.animateToStep(position + 1); - } - - @Override - public void onPageScrollStateChanged(int state) { - // unused but to be implemented due to abstract parent - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (FIRST_RUN_RESULT_CODE == requestCode && RESULT_OK == resultCode) { - - String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME); - Account account = userAccountManager.getAccountByName(accountName); - - - if (account == null) { - DisplayUtils.showSnackMessage(this, R.string.account_creation_failed); - return; - } - - userAccountManager.setCurrentOwnCloudAccount(account.name); - - Intent i = new Intent(this, FileDisplayActivity.class); - i.setAction(FileDisplayActivity.RESTART); - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); - - finish(); - } - } - - - public static FeatureItem[] getFirstRun() { - return new FeatureItem[]{ - new FeatureItem(R.drawable.logo, R.string.first_run_1_text, R.string.empty, true, false), - new FeatureItem(R.drawable.first_run_files, R.string.first_run_2_text, R.string.empty, true, false), - new FeatureItem(R.drawable.first_run_groupware, R.string.first_run_3_text, R.string.empty, true, false), - new FeatureItem(R.drawable.first_run_talk, R.string.first_run_4_text, R.string.empty, true, false)}; - } -} diff --git a/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.kt b/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.kt new file mode 100644 index 000000000000..e9080426a974 --- /dev/null +++ b/app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.kt @@ -0,0 +1,275 @@ +/* + * 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 + * + * 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 . + */ +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? = 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 + 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) + ) + } +} diff --git a/app/src/main/res/layout/first_run_activity.xml b/app/src/main/res/layout/first_run_activity.xml index 0935b9266782..8c477df66096 100644 --- a/app/src/main/res/layout/first_run_activity.xml +++ b/app/src/main/res/layout/first_run_activity.xml @@ -93,7 +93,7 @@ app:cornerRadius="@dimen/button_corner_radius" /> -