Skip to content

Commit ee3e405

Browse files
committed
implemented onboarding
1 parent 760fdcd commit ee3e405

28 files changed

+697
-161
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.nmc.android.onboarding
2+
3+
import androidx.test.espresso.Espresso.*
4+
import androidx.test.espresso.action.ViewActions.swipeLeft
5+
import androidx.test.espresso.action.ViewActions.swipeRight
6+
import androidx.test.espresso.assertion.ViewAssertions.matches
7+
import androidx.test.espresso.matcher.ViewMatchers.isClickable
8+
import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed
9+
import androidx.test.espresso.matcher.ViewMatchers.withId
10+
import androidx.test.ext.junit.rules.ActivityScenarioRule
11+
import androidx.test.ext.junit.runners.AndroidJUnit4
12+
import com.nextcloud.client.onboarding.FirstRunActivity
13+
import com.owncloud.android.AbstractIT
14+
import com.owncloud.android.R
15+
import org.junit.Rule
16+
import org.junit.Test
17+
import org.junit.runner.RunWith
18+
19+
@RunWith(AndroidJUnit4::class)
20+
class OnBoardingIT : AbstractIT() {
21+
22+
@get:Rule
23+
var activityRule = ActivityScenarioRule(FirstRunActivity::class.java)
24+
25+
@Test
26+
fun runAllOnboardingTests() {
27+
verifyUIElements()
28+
29+
shortSleep()
30+
31+
verifyOnBoardingSwipe()
32+
}
33+
34+
private fun verifyUIElements() {
35+
onView(withId(R.id.contentPanel)).check(matches(isCompletelyDisplayed()))
36+
onView(withId(R.id.progressIndicator)).check(matches(isCompletelyDisplayed()))
37+
onView(withId(R.id.login)).check(matches(isCompletelyDisplayed()))
38+
onView(withId(R.id.login)).check(matches(isClickable()))
39+
}
40+
41+
private fun verifyOnBoardingSwipe() {
42+
onView(withId(R.id.contentPanel)).perform(swipeLeft())
43+
onView(withId(R.id.contentPanel)).perform(swipeLeft())
44+
onView(withId(R.id.contentPanel)).perform(swipeLeft())
45+
46+
onView(withId(R.id.contentPanel)).perform(swipeRight())
47+
onView(withId(R.id.contentPanel)).perform(swipeRight())
48+
}
49+
}

app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.kt

Lines changed: 53 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
package com.nextcloud.client.onboarding
2525

2626
import android.accounts.AccountManager
27+
import android.annotation.SuppressLint
2728
import android.content.Intent
29+
import android.content.pm.ActivityInfo
2830
import android.content.res.Configuration
2931
import android.os.Bundle
30-
import android.view.View
31-
import android.view.ViewGroup
32-
import android.widget.LinearLayout
32+
import android.view.ViewGroup.MarginLayoutParams
3333
import androidx.activity.OnBackPressedCallback
3434
import androidx.activity.result.ActivityResult
3535
import androidx.activity.result.ActivityResultLauncher
@@ -40,14 +40,15 @@ import com.nextcloud.client.account.UserAccountManager
4040
import com.nextcloud.client.appinfo.AppInfo
4141
import com.nextcloud.client.di.Injectable
4242
import com.nextcloud.client.preferences.AppPreferences
43+
import com.nmc.android.helper.OnBoardingPagerAdapter
44+
import com.nmc.android.helper.OnBoardingUtils.Companion.getOnBoardingItems
45+
import com.nmc.android.utils.DisplayUtils.isLandscapeOrientation
4346
import com.owncloud.android.BuildConfig
4447
import com.owncloud.android.R
4548
import com.owncloud.android.authentication.AuthenticatorActivity
4649
import com.owncloud.android.databinding.FirstRunActivityBinding
47-
import com.owncloud.android.features.FeatureItem
4850
import com.owncloud.android.ui.activity.BaseActivity
4951
import com.owncloud.android.ui.activity.FileDisplayActivity
50-
import com.owncloud.android.ui.adapter.FeaturesViewAdapter
5152
import com.owncloud.android.utils.DisplayUtils
5253
import com.owncloud.android.utils.theme.ViewThemeUtils
5354
import javax.inject.Inject
@@ -82,25 +83,31 @@ class FirstRunActivity : BaseActivity(), ViewPager.OnPageChangeListener, Injecta
8283
private lateinit var binding: FirstRunActivityBinding
8384
private var defaultViewThemeUtils: ViewThemeUtils? = null
8485

86+
private var selectedPosition = 0
87+
88+
@SuppressLint("SourceLockedOrientationActivity")
8589
override fun onCreate(savedInstanceState: Bundle?) {
8690
enableAccountHandling = false
8791

8892
super.onCreate(savedInstanceState)
8993

9094
applyDefaultTheme()
9195

96+
// NMC Customization
97+
// if device is not tablet then we have to lock it to Portrait mode
98+
// as we don't have images for that
99+
if (!com.nmc.android.utils.DisplayUtils.isTablet()) {
100+
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
101+
}
102+
92103
binding = FirstRunActivityBinding.inflate(layoutInflater)
93104
setContentView(binding.root)
94105

95-
val isProviderOrOwnInstallationVisible = resources.getBoolean(R.bool.show_provider_or_own_installation)
96-
setSlideshowSize(resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE)
97-
98106
registerActivityResult()
99107
setupLoginButton()
100-
setupSignupButton(isProviderOrOwnInstallationVisible)
101-
setupHostOwnServerTextView(isProviderOrOwnInstallationVisible)
102108
deleteAccountAtFirstLaunch()
103-
setupFeaturesViewAdapter()
109+
updateLoginButtonMargin()
110+
updateOnBoardingPager(selectedPosition)
104111
handleOnBackPressed()
105112
}
106113

@@ -139,57 +146,52 @@ class FirstRunActivity : BaseActivity(), ViewPager.OnPageChangeListener, Injecta
139146
val authenticatorActivityIntent = getAuthenticatorActivityIntent(false)
140147
activityResult?.launch(authenticatorActivityIntent)
141148
} else {
149+
preferences?.onBoardingComplete = true
142150
finish()
143151
}
144152
}
145153
}
146154

147-
private fun setupSignupButton(isProviderOrOwnInstallationVisible: Boolean) {
148-
defaultViewThemeUtils?.material?.colorMaterialButtonOutlinedOnPrimary(binding.signup)
149-
binding.signup.visibility = if (isProviderOrOwnInstallationVisible) View.VISIBLE else View.GONE
150-
binding.signup.setOnClickListener {
151-
val authenticatorActivityIntent = getAuthenticatorActivityIntent(true)
152-
153-
if (intent.getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
154-
activityResult?.launch(authenticatorActivityIntent)
155-
} else {
156-
authenticatorActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
157-
startActivity(authenticatorActivityIntent)
158-
}
159-
}
160-
}
161-
162155
private fun getAuthenticatorActivityIntent(extraUseProviderAsWebLogin: Boolean): Intent {
163156
val intent = Intent(this, AuthenticatorActivity::class.java)
164157
intent.putExtra(AuthenticatorActivity.EXTRA_USE_PROVIDER_AS_WEBLOGIN, extraUseProviderAsWebLogin)
165158
return intent
166159
}
167160

168-
private fun setupHostOwnServerTextView(isProviderOrOwnInstallationVisible: Boolean) {
169-
defaultViewThemeUtils?.platform?.colorTextView(binding.hostOwnServer, ColorRole.ON_PRIMARY)
170-
binding.hostOwnServer.visibility = if (isProviderOrOwnInstallationVisible) View.VISIBLE else View.GONE
171-
if (isProviderOrOwnInstallationVisible) {
172-
binding.hostOwnServer.setOnClickListener {
173-
DisplayUtils.startLinkIntent(
174-
this,
175-
R.string.url_server_install
176-
)
177-
}
178-
}
179-
}
180-
181161
// Sometimes, accounts are not deleted when you uninstall the application so we'll do it now
182162
private fun deleteAccountAtFirstLaunch() {
183163
if (onboarding?.isFirstRun == true) {
184164
userAccountManager?.removeAllAccounts()
185165
}
186166
}
187167

188-
@Suppress("SpreadOperator")
189-
private fun setupFeaturesViewAdapter() {
190-
val featuresViewAdapter = FeaturesViewAdapter(supportFragmentManager, *firstRun)
168+
private fun updateLoginButtonMargin() {
169+
if (isLandscapeOrientation()) {
170+
if (binding.login.layoutParams is MarginLayoutParams) {
171+
(binding.login.layoutParams as MarginLayoutParams).setMargins(
172+
0, 0, 0, resources.getDimensionPixelOffset(
173+
R.dimen.login_btn_bottom_margin_land
174+
)
175+
)
176+
binding.login.requestLayout()
177+
}
178+
} else {
179+
if (binding.login.layoutParams is MarginLayoutParams) {
180+
(binding.login.layoutParams as MarginLayoutParams).setMargins(
181+
0, 0, 0, resources.getDimensionPixelOffset(
182+
R.dimen.login_btn_bottom_margin
183+
)
184+
)
185+
binding.login.requestLayout()
186+
}
187+
}
188+
}
189+
190+
private fun updateOnBoardingPager(selectedPosition: Int) {
191+
val featuresViewAdapter = OnBoardingPagerAdapter(this, getOnBoardingItems())
191192
binding.progressIndicator.setNumberOfSteps(featuresViewAdapter.count)
192193
binding.contentPanel.adapter = featuresViewAdapter
194+
binding.contentPanel.currentItem = selectedPosition
193195
binding.contentPanel.addOnPageChangeListener(this)
194196
}
195197

@@ -203,40 +205,18 @@ class FirstRunActivity : BaseActivity(), ViewPager.OnPageChangeListener, Injecta
203205
if (intent.getBooleanExtra(EXTRA_ALLOW_CLOSE, false)) {
204206
onBackPressedDispatcher.onBackPressed()
205207
} else {
206-
val intent = Intent(applicationContext, AuthenticatorActivity::class.java)
207-
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
208-
intent.putExtra(EXTRA_EXIT, true)
209-
startActivity(intent)
210-
finish()
208+
// NMC Customization
209+
finishAffinity()
211210
}
212211
}
213212
}
214213
)
215214
}
216215

217-
private fun setSlideshowSize(isLandscape: Boolean) {
218-
val isProviderOrOwnInstallationVisible = resources.getBoolean(R.bool.show_provider_or_own_installation)
219-
binding.buttonLayout.orientation = if (isLandscape) LinearLayout.HORIZONTAL else LinearLayout.VERTICAL
220-
221-
val layoutParams: LinearLayout.LayoutParams = if (isProviderOrOwnInstallationVisible) {
222-
LinearLayout.LayoutParams(
223-
ViewGroup.LayoutParams.MATCH_PARENT,
224-
ViewGroup.LayoutParams.WRAP_CONTENT
225-
)
226-
} else {
227-
@Suppress("MagicNumber")
228-
LinearLayout.LayoutParams(
229-
ViewGroup.LayoutParams.MATCH_PARENT,
230-
DisplayUtils.convertDpToPixel(if (isLandscape) 100f else 150f, this)
231-
)
232-
}
233-
234-
binding.bottomLayout.layoutParams = layoutParams
235-
}
236-
237216
override fun onConfigurationChanged(newConfig: Configuration) {
238217
super.onConfigurationChanged(newConfig)
239-
setSlideshowSize(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
218+
updateLoginButtonMargin()
219+
updateOnBoardingPager(selectedPosition)
240220
}
241221

242222
private fun onFinish() {
@@ -253,7 +233,11 @@ class FirstRunActivity : BaseActivity(), ViewPager.OnPageChangeListener, Injecta
253233
}
254234

255235
override fun onPageSelected(position: Int) {
256-
binding.progressIndicator.animateToStep(position + 1)
236+
//-1 to position because this position doesn't start from 0
237+
selectedPosition = position - 1
238+
239+
//pass directly the position here because this position will doesn't start from 0
240+
binding.progressIndicator.animateToStep(position)
257241
}
258242

259243
override fun onPageScrollStateChanged(state: Int) {
@@ -263,13 +247,5 @@ class FirstRunActivity : BaseActivity(), ViewPager.OnPageChangeListener, Injecta
263247
companion object {
264248
const val EXTRA_ALLOW_CLOSE = "ALLOW_CLOSE"
265249
const val EXTRA_EXIT = "EXIT"
266-
267-
val firstRun: Array<FeatureItem>
268-
get() = arrayOf(
269-
FeatureItem(R.drawable.logo, R.string.first_run_1_text, R.string.empty, true, false),
270-
FeatureItem(R.drawable.first_run_files, R.string.first_run_2_text, R.string.empty, true, false),
271-
FeatureItem(R.drawable.first_run_groupware, R.string.first_run_3_text, R.string.empty, true, false),
272-
FeatureItem(R.drawable.first_run_talk, R.string.first_run_4_text, R.string.empty, true, false)
273-
)
274250
}
275251
}

app/src/main/java/com/nextcloud/client/onboarding/OnboardingServiceImpl.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,7 @@ internal class OnboardingServiceImpl constructor(
7272
}
7373

7474
override fun launchFirstRunIfNeeded(activity: Activity): Boolean {
75-
val isProviderOrOwnInstallationVisible = resources.getBoolean(R.bool.show_provider_or_own_installation)
76-
val canLaunch = isProviderOrOwnInstallationVisible && isFirstRun && activity is AuthenticatorActivity
75+
val canLaunch = !preferences.onBoardingComplete && activity is AuthenticatorActivity
7776
if (canLaunch) {
7877
val intent = Intent(activity, FirstRunActivity::class.java)
7978
activity.startActivityForResult(intent, AuthenticatorActivity.REQUEST_CODE_FIRST_RUN)

app/src/main/java/com/nextcloud/client/preferences/AppPreferences.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,10 @@ default void onDarkThemeModeChanged(DarkMode mode) {
378378

379379
void setCalendarLastBackup(long timestamp);
380380

381+
void setOnBoardingComplete(boolean isCompleted);
382+
383+
boolean getOnBoardingComplete();
384+
381385
void setPdfZoomTipShownCount(int count);
382386

383387
int getPdfZoomTipShownCount();

app/src/main/java/com/nextcloud/client/preferences/AppPreferencesImpl.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ public final class AppPreferencesImpl implements AppPreferences {
8989
private static final String PREF__FOLDER_SORT_ORDER = "folder_sort_order";
9090
private static final String PREF__FOLDER_LAYOUT = "folder_layout";
9191

92+
private static final String PREF__ON_BOARDING_COMPLETE = "on_boarding_complete";
93+
9294
private static final String PREF__LOCK_TIMESTAMP = "lock_timestamp";
9395
private static final String PREF__SHOW_MEDIA_SCAN_NOTIFICATIONS = "show_media_scan_notifications";
9496
private static final String PREF__LOCK = SettingsActivity.PREFERENCE_LOCK;
@@ -718,6 +720,16 @@ public void setCalendarLastBackup(long timestamp) {
718720
preferences.edit().putLong(PREF__CALENDAR_LAST_BACKUP, timestamp).apply();
719721
}
720722

723+
@Override
724+
public void setOnBoardingComplete(boolean isCompleted) {
725+
preferences.edit().putBoolean(PREF__ON_BOARDING_COMPLETE, isCompleted).apply();
726+
}
727+
728+
@Override
729+
public boolean getOnBoardingComplete() {
730+
return preferences.getBoolean(PREF__ON_BOARDING_COMPLETE, false);
731+
}
732+
721733
@Override
722734
public void setPdfZoomTipShownCount(int count) {
723735
preferences.edit().putInt(PREF__PDF_ZOOM_TIP_SHOWN, count).apply();

0 commit comments

Comments
 (0)