Skip to content

Commit

Permalink
Merge pull request #566 from KasperskyLab/ISSUE-372-update-tutorial
Browse files Browse the repository at this point in the history
Edit examples for screenshot test lesson
  • Loading branch information
sumin93 authored Sep 7, 2023
2 parents e8e8b5d + f60a360 commit f402954
Show file tree
Hide file tree
Showing 16 changed files with 319 additions and 1 deletion.
10 changes: 10 additions & 0 deletions tutorial/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ plugins {

android {
defaultConfig {
minSdk = 21

applicationId = "com.kaspersky.kaspresso.tutorial"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments["clearPackageData"] = "true"
}

packagingOptions {
exclude("META-INF/LICENSE.md")
exclude("META-INF/LICENSE-notice.md")
}

testOptions {
execution = "ANDROIDX_TEST_ORCHESTRATOR"
}
Expand All @@ -20,5 +26,9 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.5.1")
implementation("com.google.android.material:material:1.7.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.5.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1")
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.google.code.gson:gson:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
androidTestImplementation("androidx.test.ext:junit-ktx:1.1.4")
}
4 changes: 4 additions & 0 deletions tutorial/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@
<activity
android:name=".lists.NoteListActivity"
android:exported="true" />

<activity
android:name=".user.LoadUserActivity"
android:exported="true" />
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.kaspersky.kaspresso.tutorial.login.LoginActivity
import com.kaspersky.kaspresso.tutorial.notification.NotificationActivity
import com.kaspersky.kaspresso.tutorial.permission.MakeCallActivity
import com.kaspersky.kaspresso.tutorial.simple.SimpleActivity
import com.kaspersky.kaspresso.tutorial.user.LoadUserActivity
import com.kaspersky.kaspresso.tutorial.wifi.WiFiActivity

class MainActivity : AppCompatActivity() {
Expand Down Expand Up @@ -45,5 +46,8 @@ class MainActivity : AppCompatActivity() {
binding.listActivityBtn.setOnClickListener {
startActivity(Intent(this, NoteListActivity::class.java))
}
binding.loadUserActivityBtn.setOnClickListener {
startActivity(Intent(this, LoadUserActivity::class.java))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.kaspersky.kaspresso.tutorial.user

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object ApiFactory {

private val retrofit = Retrofit.Builder()
.baseUrl("https://random-data-api.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()

val apiService = retrofit.create(ApiService::class.java)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.kaspersky.kaspresso.tutorial.user

import retrofit2.http.GET

interface ApiService {

@GET("api/users/random_user")
suspend fun loadUser(): User
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.kaspersky.kaspresso.tutorial.user

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.kaspersky.kaspresso.tutorial.R

class LoadUserActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_load_user)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container, LoadUserFragment.newInstance())
.commit()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package com.kaspersky.kaspresso.tutorial.user

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.kaspersky.kaspresso.tutorial.databinding.FragmentLoadUserBinding
import kotlinx.coroutines.launch

class LoadUserFragment : Fragment() {

private var _binding: FragmentLoadUserBinding? = null
private val binding: FragmentLoadUserBinding
get() = _binding ?: throw IllegalStateException("FragmentLoadUserBinding is null")

private lateinit var viewModel: LoadUserViewModel

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
_binding = FragmentLoadUserBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = ViewModelProvider(this)[LoadUserViewModel::class.java]
binding.loadingButton.setOnClickListener {
viewModel.loadUser()
}
observeViewModel()
}

private fun observeViewModel() {
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.state.collect { state ->
when (state) {
State.Initial -> {
binding.progressBarLoading.isVisible = false
binding.loadingButton.isEnabled = true
binding.error.isVisible = false
binding.username.isVisible = false
}
is State.Content -> {
binding.progressBarLoading.isVisible = false
binding.loadingButton.isEnabled = true
binding.error.isVisible = false
binding.username.isVisible = true

val user = state.user
binding.username.text = "${user.name} ${user.lastName}"
}
State.Error -> {
binding.progressBarLoading.isVisible = false
binding.loadingButton.isEnabled = true
binding.error.isVisible = true
binding.username.isVisible = false
}
State.Progress -> {
binding.progressBarLoading.isVisible = true
binding.loadingButton.isEnabled = false
binding.error.isVisible = false
binding.username.isVisible = false
}
}
}
}
}
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}

companion object {

fun newInstance(): LoadUserFragment = LoadUserFragment()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.kaspersky.kaspresso.tutorial.user

object LoadUserRepository {

private val apiService = ApiFactory.apiService

suspend fun loadUser(): User = apiService.loadUser()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.kaspersky.kaspresso.tutorial.user

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class LoadUserViewModel : ViewModel() {

private val repository = LoadUserRepository

private val _state = MutableStateFlow<State>(State.Initial)
val state = _state.asStateFlow()

fun loadUser() {
viewModelScope.launch {
_state.value = State.Progress
try {
val user = repository.loadUser()
_state.value = State.Content(user)
} catch (e: Exception) {
_state.value = State.Error
}
}
}
}

sealed class State {

data class Content(val user: User) : State()

object Progress : State()

object Error : State()

object Initial : State()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.kaspersky.kaspresso.tutorial.user

import com.google.gson.annotations.SerializedName

data class User(
@SerializedName("first_name") val name: String,
@SerializedName("last_name") val lastName: String
)
9 changes: 9 additions & 0 deletions tutorial/src/main/res/layout/activity_load_user.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.fragment.app.FragmentContainerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp" />
7 changes: 7 additions & 0 deletions tutorial/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,12 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="List activity" />

<Button
android:id="@+id/load_user_activity_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Load user activity" />
</LinearLayout>
</ScrollView>
59 changes: 59 additions & 0 deletions tutorial/src/main/res/layout/fragment_load_user.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">

<TextView
android:id="@+id/username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:textSize="24sp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/loading_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="John Smith"
tools:visibility="visible" />

<TextView
android:id="@+id/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/something_went_wrong"
android:textColor="@android:color/holo_red_light"
android:textSize="24sp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/loading_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible" />

<ProgressBar
android:id="@+id/progress_bar_loading"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_marginBottom="16dp"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/loading_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:visibility="visible" />

<Button
android:id="@+id/loading_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorPrimary"
android:text="@string/load_user"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
41 changes: 41 additions & 0 deletions tutorial/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Tutoriel</string>

<!-- Simple Activity screen -->
<string name="simple_activity_default_title">Titre par défaut</string>
<string name="simple_activity_input_hint">Texte d\'entrée</string>
<string name="simple_activity_change_title_button">Modifier le titre</string>

<!-- Wifi Activity screen -->
<string name="enabled_status">permettre</string>
<string name="disabled_status">désactivée</string>

<!-- Notification Activity screen -->
<string name="show_notification_button">afficher la notification</string>
<string name="notification_title">Titre de la Notification</string>
<string name="notification_content">Contenu de la Notification</string>

<!-- Login Activity screen -->
<string name="login_activity_hint_username">TODO: add french locale</string>
<string name="login_activity_hint_password">TODO: add french locale</string>
<string name="login_activity_button_login">TODO: add french locale</string>

<!-- After Login screens -->
<string name="screen_after_login">Écran après autorisation</string>

<!-- Make call screen-->
<string name="phone_number_hint">Numéro de téléphone:</string>
<string name="make_call_btn">Passer un Appel</string>

<!-- Flaky Screen -->
<string name="text_1">Texte 1</string>
<string name="text_2">Texte 2</string>
<string name="text_3">Texte 3</string>
<string name="text_4">Texte 4</string>
<string name="text_5">Texte 5</string>

<!-- Screenshot sample-->
<string name="something_went_wrong">Quelque chose s\'est mal passé</string>
<string name="load_user">Charger l\'utilisateur</string>
</resources>
2 changes: 1 addition & 1 deletion tutorial/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

<color name="colorPrimary">#008577</color>
<color name="colorPrimaryDark">#00574B</color>
<color name="colorAccent">#FFFFFFFF</color>
<color name="colorAccent">#008577</color>

<color name="customTextColor">#FF6200EE</color>
</resources>
4 changes: 4 additions & 0 deletions tutorial/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@
<string name="text_3">Text 3</string>
<string name="text_4">Text 4</string>
<string name="text_5">Text 5</string>

<!-- Screenshot sample-->
<string name="something_went_wrong">Something went wrong</string>
<string name="load_user">Load User</string>
</resources>

0 comments on commit f402954

Please sign in to comment.