Add error messages instead of toasts

This commit is contained in:
Matthieu 2020-10-31 11:21:56 +01:00
parent 40f4d03bd1
commit 2e88e49875
19 changed files with 306 additions and 67 deletions

View File

@ -66,15 +66,15 @@ dependencies {
*/
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.navigation:navigation-fragment:2.3.0'
implementation 'androidx.navigation:navigation-ui:2.3.0'
implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
implementation "androidx.browser:browser:1.2.0"
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
implementation 'androidx.paging:paging-runtime-ktx:2.1.2'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
@ -83,14 +83,14 @@ dependencies {
implementation 'androidx.gridlayout:gridlayout:1.0.0'
// Use the most recent version of CameraX
def camerax_version = '1.0.0-beta08'
def camerax_version = '1.0.0-beta11'
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"
// CameraX Lifecycle library
implementation "androidx.camera:camera-lifecycle:$camerax_version"
// CameraX View class
implementation 'androidx.camera:camera-view:1.0.0-alpha15'
implementation 'androidx.camera:camera-view:1.0.0-alpha18'
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
@ -106,13 +106,13 @@ dependencies {
implementation 'com.google.android.material:material:1.2.1'
//Dagger (dependency injection)
implementation 'com.google.dagger:dagger-android:2.28.3'
implementation 'com.google.dagger:dagger-android-support:2.28.3'
implementation 'com.google.dagger:dagger-android:2.29.1'
implementation 'com.google.dagger:dagger-android-support:2.29.1'
// if you use the support libraries
kapt 'com.google.dagger:dagger-android-processor:2.28.3'
kapt 'com.google.dagger:dagger-compiler:2.28.3'
kapt 'com.google.dagger:dagger-android-processor:2.29.1'
kapt 'com.google.dagger:dagger-compiler:2.29.1'
implementation 'com.squareup.okhttp3:okhttp:4.8.1'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
@ -160,9 +160,9 @@ dependencies {
debugImplementation "androidx.fragment:fragment-testing:1.2.5"
testImplementation 'com.github.tomakehurst:wiremock-jre8:2.27.1'
testImplementation 'com.github.tomakehurst:wiremock-jre8:2.27.2'
testImplementation "com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0"
testImplementation 'junit:junit:4.13'
testImplementation 'junit:junit:4.13.1'
testImplementation "androidx.room:room-testing:$room_version"
@ -175,7 +175,7 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.3.0'
androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.2'
androidTestImplementation('com.squareup.okhttp3:mockwebserver:4.8.0')
androidTestImplementation('com.squareup.okhttp3:mockwebserver:4.9.0')
}

View File

@ -220,7 +220,7 @@ class CameraFragment : Fragment() {
)
// Attach the viewfinder's surface provider to preview use case
preview?.setSurfaceProvider(viewFinder.createSurfaceProvider())
preview?.setSurfaceProvider(viewFinder.surfaceProvider)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}

View File

@ -9,28 +9,27 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.*
import androidx.annotation.StringRes
import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat.getSystemService
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.textview.MaterialTextView
import com.h.pixeldroid.Pixeldroid
import com.h.pixeldroid.PostActivity
import com.h.pixeldroid.R
import com.h.pixeldroid.SearchActivity
import com.h.pixeldroid.api.PixelfedAPI
import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.di.PixelfedAPIHolder
import com.h.pixeldroid.objects.DiscoverPost
import com.h.pixeldroid.objects.DiscoverPosts
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.DBUtils
import com.h.pixeldroid.utils.ImageConverter
import com.mikepenz.iconics.IconicsColor
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.padding
import com.mikepenz.iconics.utils.color
import com.mikepenz.iconics.utils.colorInt
import com.mikepenz.iconics.utils.paddingDp
import com.mikepenz.iconics.utils.sizeDp
import kotlinx.android.synthetic.main.fragment_search.*
@ -85,6 +84,7 @@ class SearchDiscoverFragment : Fragment() {
discoverText.setCompoundDrawables(IconicsDrawable(requireContext(), GoogleMaterial.Icon.gmd_explore).apply {
sizeDp = 24
paddingDp = 20
color = IconicsColor.colorRes(R.color.colorDrawing)
}, null, null, null)
return view
@ -107,12 +107,24 @@ class SearchDiscoverFragment : Fragment() {
}
}
fun showError(@StringRes errorText: Int = R.string.loading_toast, show: Boolean = true){
if(show){
motionLayout.transitionToEnd()
} else {
motionLayout.transitionToStart()
}
discoverRefreshLayout.isRefreshing = false
discoverProgressBar.visibility = View.GONE
}
private fun getDiscover() {
api.discover("Bearer $accessToken")
.enqueue(object : Callback<DiscoverPosts> {
override fun onFailure(call: Call<DiscoverPosts>, t: Throwable) {
showError()
Log.e("SearchDiscoverFragment:", t.toString())
}
@ -120,8 +132,10 @@ class SearchDiscoverFragment : Fragment() {
if(response.code() == 200) {
val discoverPosts = response.body()!!
adapter.addPosts(discoverPosts.posts)
discoverProgressBar.visibility = View.GONE
discoverRefreshLayout.isRefreshing = false
showError(show = false)
}
else {
showError()
}
}
})

View File

@ -72,6 +72,8 @@ open class AccountListFragment : FeedFragment() {
})
swipeRefreshLayout.setOnRefreshListener {
showError(show = false)
//by invalidating data, loadInitial will be called again
factory.liveData.value!!.invalidate()
}
@ -135,14 +137,14 @@ open class AccountListFragment : FeedFragment() {
val data = response.body()!!
callback.onResult(data)
} else{
Toast.makeText(context, getString(R.string.loading_toast), Toast.LENGTH_SHORT).show()
showError()
}
swipeRefreshLayout.isRefreshing = false
loadingIndicator.visibility = View.GONE
}
override fun onFailure(call: Call<List<Account>>, t: Throwable) {
Toast.makeText(context, getString(R.string.feed_failed), Toast.LENGTH_SHORT).show()
showError(errorText = R.string.feed_failed)
Log.e("AccountListFragment", t.toString())
}
})

View File

@ -1,11 +1,14 @@
package com.h.pixeldroid.fragments.feeds
package com.h.pixeldroid.fragments.feeds
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ProgressBar
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import androidx.paging.DataSource
@ -22,6 +25,7 @@ import com.h.pixeldroid.db.AppDatabase
import com.h.pixeldroid.db.UserDatabaseEntity
import com.h.pixeldroid.di.PixelfedAPIHolder
import com.h.pixeldroid.objects.FeedContent
import kotlinx.android.synthetic.main.fragment_feed.*
import kotlinx.android.synthetic.main.fragment_feed.view.*
import retrofit2.Call
import javax.inject.Inject
@ -65,6 +69,16 @@ open class FeedFragment: Fragment() {
return view
}
fun showError(@StringRes errorText: Int = R.string.loading_toast, show: Boolean = true){
if(show){
errorLayout.visibility = VISIBLE
progressBar.visibility = GONE
} else {
errorLayout.visibility = GONE
progressBar.visibility = VISIBLE
}
}
open inner class FeedDataSourceFactory<ObjectId, APIObject: FeedContent>(
private val dataSource: FeedDataSource<ObjectId, APIObject>
): DataSource.Factory<ObjectId, APIObject>() {

View File

@ -10,7 +10,6 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.paging.LivePagedListBuilder
@ -86,6 +85,8 @@ class NotificationsFragment : FeedFragment() {
})
swipeRefreshLayout.setOnRefreshListener {
showError(show = false)
//by invalidating data, loadInitial will be called again
factory.liveData.value!!.invalidate()
}
@ -125,15 +126,15 @@ class NotificationsFragment : FeedFragment() {
if (response.isSuccessful && response.body() != null) {
val data = response.body()!!
callback.onResult(data)
} else{
Toast.makeText(context, getString(R.string.loading_toast), Toast.LENGTH_SHORT).show()
} else {
showError()
}
swipeRefreshLayout.isRefreshing = false
loadingIndicator.visibility = View.GONE
}
override fun onFailure(call: Call<List<Notification>>, t: Throwable) {
Toast.makeText(context, getString(R.string.feed_failed), Toast.LENGTH_SHORT).show()
showError(errorText = R.string.feed_failed)
Log.e("NotificationsFragment", t.toString())
}
})

View File

@ -53,15 +53,15 @@ class HomeTimelineFragment: PostsFeedFragment() {
val notifications = response.body()!!
callback.onResult(notifications)
DBUtils.storePosts(db, notifications, user!!)
} else{
Toast.makeText(context, getString(R.string.loading_toast), Toast.LENGTH_SHORT).show()
} else {
showError()
}
swipeRefreshLayout.isRefreshing = false
loadingIndicator.visibility = View.GONE
}
override fun onFailure(call: Call<List<Status>>, t: Throwable) {
Toast.makeText(context, getString(R.string.feed_failed), Toast.LENGTH_SHORT).show()
showError(errorText = R.string.feed_failed)
Log.e("PostsFeedFragment", t.toString())
}
})

View File

@ -68,6 +68,8 @@ abstract class PostsFeedFragment : FeedFragment() {
})
swipeRefreshLayout.setOnRefreshListener {
showError(show = false)
//by invalidating data, loadInitial will be called again
factory.liveData.value!!.invalidate()
}

View File

@ -34,14 +34,14 @@ class PublicTimelineFragment: PostsFeedFragment() {
val notifications = response.body()!!
callback.onResult(notifications)
} else{
Toast.makeText(context, getString(R.string.loading_toast), Toast.LENGTH_SHORT).show()
showError()
}
swipeRefreshLayout.isRefreshing = false
loadingIndicator.visibility = View.GONE
}
override fun onFailure(call: Call<List<Status>>, t: Throwable) {
Toast.makeText(context, getString(R.string.feed_failed), Toast.LENGTH_SHORT).show()
showError(errorText = R.string.feed_failed)
Log.e("PublicTimelineFragment", t.toString())
}
})

View File

@ -77,14 +77,14 @@ class SearchAccountFragment: AccountListFragment(){
callback.onResult(notifications as List<Account>)
} else{
Toast.makeText(context, getString(R.string.loading_toast), Toast.LENGTH_SHORT).show()
showError()
}
swipeRefreshLayout.isRefreshing = false
loadingIndicator.visibility = View.GONE
}
override fun onFailure(call: Call<Results>, t: Throwable) {
Toast.makeText(context,getString(R.string.feed_failed), Toast.LENGTH_SHORT).show()
showError(errorText = R.string.feed_failed)
Log.e("FeedFragment", t.toString())
}
})

View File

@ -59,6 +59,8 @@ class SearchHashtagFragment: FeedFragment(){
})
swipeRefreshLayout.setOnRefreshListener {
showError(show = false)
//by invalidating data, loadInitial will be called again
factory.liveData.value!!.invalidate()
}
@ -107,14 +109,14 @@ class SearchHashtagFragment: FeedFragment(){
callback.onResult(notifications as List<Tag>)
} else{
Toast.makeText(context,getString(R.string.loading_toast), Toast.LENGTH_SHORT).show()
showError()
}
swipeRefreshLayout.isRefreshing = false
loadingIndicator.visibility = View.GONE
}
override fun onFailure(call: Call<Results>, t: Throwable) {
Toast.makeText(context,getString(R.string.feed_failed), Toast.LENGTH_SHORT).show()
showError(errorText = R.string.feed_failed)
Log.e("FeedFragment", t.toString())
}
})

View File

@ -8,6 +8,7 @@ import android.view.ViewGroup
import androidx.lifecycle.LiveData
import androidx.paging.LivePagedListBuilder
import androidx.paging.PagedList
import com.h.pixeldroid.R
import com.h.pixeldroid.fragments.feeds.FeedFragment
import com.h.pixeldroid.fragments.feeds.postFeeds.PostsFeedFragment
import com.h.pixeldroid.objects.Results
@ -68,15 +69,15 @@ class SearchPostsFragment: PostsFeedFragment(){
if (response.code() == 200) {
val notifications = response.body()!!.statuses as ArrayList<Status>
callback.onResult(notifications as List<Status>)
} else{
Log.e("FeedFragment", "got response code ${response.code()}")
} else {
showError()
}
swipeRefreshLayout.isRefreshing = false
loadingIndicator.visibility = View.GONE
}
override fun onFailure(call: Call<Results>, t: Throwable) {
showError(errorText = R.string.feed_failed)
Log.e("FeedFragment", t.toString())
}
})

View File

@ -0,0 +1,81 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="80dp"
android:viewportWidth="64"
android:viewportHeight="80">
<path
android:fillColor="#FF000000"
android:pathData="M42,54H40c0,-5.646 -7.311,-14 -23,-14V38C34.242,38 42,47.356 42,54Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M21.0394,38.7261l1.9971,-7.0007l1.9242,0.5489l-1.9971,7.0007z"/>
<path
android:fillColor="#FF000000"
android:pathData="M32,24a2.025,2.025 0,0 1,-1.568 -0.721l-1,-1.2a1.818,1.818 0,0 1,-0.26 -1.954A1.984,1.984 0,0 1,31 19h2a1.984,1.984 0,0 1,1.827 1.127,1.818 1.818,0 0,1 -0.259,1.953l-1,1.2A2.026,2.026 0,0 1,32 24ZM31.132,21 L31.968,22 32.905,20.943Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M37.394,20a1.376,1.376 0,0 1,-1 -0.4c-0.669,-0.669 -0.48,-1.829 0.448,-2.756s2.087,-1.117 2.756,-0.448 0.48,1.829 -0.448,2.756A2.589,2.589 0,0 1,37.394 20Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M26.606,20a2.589,2.589 0,0 1,-1.76 -0.846c-0.928,-0.927 -1.117,-2.087 -0.448,-2.756s1.828,-0.481 2.756,0.448 1.117,2.087 0.448,2.756A1.376,1.376 0,0 1,26.606 20Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M50.707,15.707l-1.414,-1.414c2,-2 2.595,-8.817 2.691,-12.293H50c-7.287,0 -9.3,1.71 -9.314,1.728a1.039,1.039 0,0 1,-1.031 0.21A19.494,19.494 0,0 0,33 3H31V1h2a22.413,22.413 0,0 1,6.834 0.886C40.9,1.216 43.713,0 50,0h3a1,1 0,0 1,1 1C54,2.168 53.907,12.507 50.707,15.707Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M34,34H30V32h4c14.617,0 18.019,-6.558 18.788,-9.11a4.9,4.9 0,0 1,-2.495 -1.183A1,1 0,0 1,51 20a3.81,3.81 0,0 0,2.221 -1.388c-2.275,-0.976 -4.387,-3.662 -6.6,-6.472l-0.41,-0.521A1,1 0,0 1,46 11C46,8.514 49.383,3.2 52.293,0.293l1.414,1.414c-2.766,2.766 -5.38,7.168 -5.679,8.982l0.169,0.215C50.444,13.762 52.991,17 55,17a1,1 0,0 1,0.832 1.555,10.9 10.9,0 0,1 -2.254,2.426 1.7,1.7 0,0 1,1.16 0.344,1 1,0 0,1 0.258,0.766C54.952,22.577 53.687,34 34,34Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M13.293,15.707C10.093,12.507 10,2.168 10,1a1,1 0,0 1,1 -1h3c6.287,0 9.1,1.216 10.166,1.886A22.413,22.413 0,0 1,31 1V3a19.494,19.494 0,0 0,-6.655 0.938,0.992 0.992,0 0,1 -1.052,-0.231h0S21.281,2 14,2H12.016c0.1,3.476 0.689,10.291 2.691,12.293Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M30,34C10.313,34 9.048,22.577 9,22.091A1,1 0,0 1,10 21c0.147,0 0.289,-0.007 0.422,-0.019a10.9,10.9 0,0 1,-2.254 -2.426A1,1 0,0 1,9 17c2.009,0 4.556,-3.238 6.8,-6.1l0.169,-0.215c-0.3,-1.814 -2.913,-6.216 -5.679,-8.982L11.707,0.293C14.617,3.2 18,8.514 18,11a1,1 0,0 1,-0.215 0.619l-0.41,0.521c-2.209,2.809 -4.319,5.494 -6.593,6.471A3.824,3.824 0,0 0,13 20a1,1 0,0 1,0.707 1.707,4.908 4.908,0 0,1 -2.5,1.184C11.979,25.438 15.377,32 30,32Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M40,64H14C4.972,64 0,59.383 0,51c0,-7.411 7.309,-13 17,-13v2C8.448,40 2,44.729 2,51c0,9.092 6.525,11 12,11H40c4.087,0 10,-2.493 10,-7V53c0,-1.638 -0.424,-2.351 -1.469,-3.949a0.8,0.8 0,0 1,-0.054 -0.095l-8.369,-16.5 1.784,-0.9L50.235,48A7.987,7.987 0,0 1,52 53v2C52,60.872 45.031,64 40,64Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M17.99,11.109A0.518,0.518 0,0 0,18 11H16c0,-1.488 5.386,-9 8,-9V4C22.744,4.113 18.309,9.836 17.99,11.109Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M46.01,11.109c-0.319,-1.273 -4.754,-7 -6.017,-7.109L40,2c2.614,0 8,7.512 8,9H46A0.518,0.518 0,0 0,46.01 11.109Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M32,34c-3.5,0 -10,0 -10,-6 0,-3.406 4.336,-7.849 8.754,-8.97l0.492,1.94C27.514,21.916 24,25.732 24,28c0,3.7 3.623,4 8,4s8,-0.3 8,-4c0,-2.265 -3.514,-6.081 -7.247,-7.031l0.494,-1.938C37.664,20.155 42,24.6 42,28 42,34 35.495,34 32,34Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M37,16a2.754,2.754 0,0 1,-3 -2.5A2.754,2.754 0,0 1,37 11a2.754,2.754 0,0 1,3 2.5A2.754,2.754 0,0 1,37 16ZM37,13c-0.62,0 -1,0.323 -1,0.5s0.38,0.5 1,0.5 1,-0.323 1,-0.5S37.62,13 37,13Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M27,16a2.754,2.754 0,0 1,-3 -2.5A2.754,2.754 0,0 1,27 11a2.754,2.754 0,0 1,3 2.5A2.754,2.754 0,0 1,27 16ZM27,13c-0.62,0 -1,0.323 -1,0.5s0.38,0.5 1,0.5 1,-0.323 1,-0.5S27.62,13 27,13Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M42.956,30a1,1 0,0 1,-0.875 -1.485c0.789,-1.421 1.11,-2.244 0.932,-3.357 -0.1,-0.632 -0.306,-1.075 -0.547,-1.187a2.132,2.132 0,0 1,-0.819 -0.721,3.262 3.262,0 0,1 -0.476,-2.984c0.354,-1.034 1.3,-2.266 3.8,-2.266C47.683,18 49,19.517 49,22.637 49,26.6 45.677,30 42.956,30ZM44.974,20c-1.6,0 -1.818,0.642 -1.912,0.916a1.263,1.263 0,0 0,0.2 1.153,0.654 0.654,0 0,0 0.1,0.121 3.237,3.237 0,0 1,1.623 2.653,5.327 5.327,0 0,1 -0.109,2.264A6.114,6.114 0,0 0,47 22.637C47,20.184 46.2,20 44.974,20Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M21.044,30C18.323,30 15,26.6 15,22.637 15,19.517 16.317,18 19.026,18c2.5,0 3.449,1.232 3.8,2.266a3.265,3.265 0,0 1,-0.478 2.987,2.135 2.135,0 0,1 -0.823,0.721c-0.235,0.109 -0.44,0.552 -0.541,1.183 -0.178,1.114 0.143,1.937 0.932,3.358A1,1 0,0 1,21.044 30ZM19.026,20C17.8,20 17,20.184 17,22.637a6.114,6.114 0,0 0,2.122 4.47,5.332 5.332,0 0,1 -0.109,-2.265 3.285,3.285 0,0 1,1.652 -2.672s0.026,-0.036 0.07,-0.1a1.265,1.265 0,0 0,0.2 -1.156C20.844,20.642 20.623,20 19.026,20Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M31,23h2v2h-2z"/>
<path
android:fillColor="#FF000000"
android:pathData="M34.445,27.832 L32,26.2l-2.445,1.63 -1.11,-1.664 3,-2a1,1 0,0 1,1.11 0l3,2Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M14,64c-4.363,0 -9,-4.557 -9,-13 0,-5.508 2.054,-10 5.494,-12.009l1.01,1.727C8.684,42.366 7,46.21 7,51c0,6.886 3.56,11 7,11Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M22,64c-4.363,0 -9,-4.557 -9,-13s4.637,-13 9,-13v2c-3.44,0 -7,4.114 -7,11s3.56,11 7,11Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M29,64c-4.363,0 -9,-4.557 -9,-13 0,-5.508 2.054,-10 5.494,-12.009l1.01,1.727C23.684,42.366 22,46.21 22,51c0,6.886 3.56,11 7,11Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M37,64c-4.363,0 -9,-4.557 -9,-13 0,-4.888 1.539,-7.923 2.83,-9.608l1.588,1.216C31.314,44.048 30,46.673 30,51c0,6.886 3.56,11 7,11Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M45,63c-4.479,0 -9,-5.257 -9,-17h2c0,9.848 3.521,15 7,15Z"/>
<path
android:fillColor="#FF000000"
android:pathData="M37,36h2v11h-2z"/>
</vector>

View File

@ -1,22 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<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:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"/>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layoutManager="LinearLayoutManager" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
@ -24,5 +24,52 @@
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/errorLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible">
<ImageView
android:id="@+id/imageView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="@color/colorDrawing"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/red_panda" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Something went wrong..."
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView4" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This panda is not happy. Pull to refresh to try again."
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -40,24 +40,71 @@
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motionLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
app:layoutDescription="@xml/fragment_search_xml_error_scene"
app:layout_constraintBottom_toTopOf="@+id/discoverList"
app:layout_constraintTop_toTopOf="@+id/discoverList">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/discoverErrorLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/imageView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/red_panda"
app:tint="@color/colorDrawing" />
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Something went wrong..."
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView4" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This panda is not happy. Pull to refresh to try again."
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/discoverText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:text="@string/discover"
android:layout_gravity="center_horizontal"/>
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/discoverErrorLayout" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/discoverList"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"/>
android:nestedScrollingEnabled="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/discoverText" />
</LinearLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -2,15 +2,8 @@
<resources>
<color name="colorPrimary">#FFFFFF</color>
<color name="colorPrimaryTab">#6200EE</color>
<color name="colorPrimaryActionBar">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
<color name="colorButtonBg">#6200EE</color>
<color name="colorButtonText">#FFFFFF</color>
<color name="filterLabelNormal">#8A8889</color>
<color name="filterLabelSelected">#221F20</color>
<color name="colorPrimaryError">#FF0000</color>
<color name="colorText">#000000</color>
<color name="colorDrawing">#FFFFFF</color>
</resources>

View File

@ -14,4 +14,5 @@
<color name="filterLabelSelected">#221F20</color>
<color name="colorPrimaryError">#FF0000</color>
<color name="colorText">#FFFFFF</color>
<color name="colorDrawing">#000000</color>
</resources>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<MotionScene
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<Transition
android:id="@+id/transition"
app:constraintSetEnd="@+id/end"
app:constraintSetStart="@id/start"
app:duration="500">
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/discoverErrorLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="parent" />
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/discoverErrorLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</ConstraintSet>
</MotionScene>

View File

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.4.0'
ext.kotlin_version = '1.4.10'
repositories {
google()
jcenter()