diff --git a/albumlist/src/main/java/com/hako/albumlist/domain/usecase/GetAlbum.kt b/albumlist/src/main/java/com/hako/albumlist/domain/usecase/GetAlbum.kt index 8ec47e6..fe59945 100644 --- a/albumlist/src/main/java/com/hako/albumlist/domain/usecase/GetAlbum.kt +++ b/albumlist/src/main/java/com/hako/albumlist/domain/usecase/GetAlbum.kt @@ -3,7 +3,7 @@ package com.hako.albumlist.domain.usecase import com.hako.albumlist.domain.datasource.AlbumlistRemoteApi import com.hako.albumlist.model.AlbumViewable import com.hako.albumlist.model.toAlbumEntity -import com.hako.albumlist.model.toUserViewable +import com.hako.albumlist.model.toAlbumViewable import com.hako.base.domain.database.dao.AlbumDao import io.reactivex.Single import io.reactivex.schedulers.Schedulers @@ -28,13 +28,13 @@ class GetAlbum(private val dao: AlbumDao) : KoinComponent { api.getAlbums(userId) .doOnSuccess { dao.saveAll(it.map { album -> album.toAlbumEntity() }) - onSuccess(dao.getAlbums(userId).map { album -> album.toUserViewable() }) + onSuccess(dao.getAlbums(userId).map { album -> album.toAlbumViewable() }) } .doOnSubscribe { onLoading() } .subscribeOn(Schedulers.io()) .subscribe({}, { onError(it) }) } else { - onSuccess(dbAlbum.map { it.toUserViewable() }) + onSuccess(dbAlbum.map { it.toAlbumViewable() }) } } .subscribe() diff --git a/albumlist/src/main/java/com/hako/albumlist/model/AlbumModels.kt b/albumlist/src/main/java/com/hako/albumlist/model/AlbumModels.kt index c61f6b7..fde8f21 100644 --- a/albumlist/src/main/java/com/hako/albumlist/model/AlbumModels.kt +++ b/albumlist/src/main/java/com/hako/albumlist/model/AlbumModels.kt @@ -20,5 +20,5 @@ data class AlbumViewable( fun Album.toAlbumEntity() = AlbumEntity(this.id, this.userId, this.title) -fun AlbumEntity.toUserViewable() = AlbumViewable(this.id, this.userId, this.title) +fun AlbumEntity.toAlbumViewable() = AlbumViewable(this.id, this.userId, this.title) diff --git a/albumlist/src/main/java/com/hako/albumlist/viewmodel/AlbumlistViewmodel.kt b/albumlist/src/main/java/com/hako/albumlist/viewmodel/AlbumlistViewmodel.kt index f3f3bbc..ed795b4 100644 --- a/albumlist/src/main/java/com/hako/albumlist/viewmodel/AlbumlistViewmodel.kt +++ b/albumlist/src/main/java/com/hako/albumlist/viewmodel/AlbumlistViewmodel.kt @@ -17,10 +17,10 @@ class AlbumlistViewmodel : ViewModel(), KoinComponent { val data = MutableLiveData>>() val requestStatus = MutableLiveData() - private val getUsers: GetAlbum = get() + private val getAlbum: GetAlbum = get() fun fetchAlbums(userId: Int) { - getUsers.execute( + getAlbum.execute( userId, onSuccess = { requestStatus.postValue(Ready) diff --git a/albumlist/src/main/java/com/hako/albumlist/widget/AlbumlistAdapter.kt b/albumlist/src/main/java/com/hako/albumlist/widget/AlbumlistAdapter.kt index fd646a7..a67596a 100644 --- a/albumlist/src/main/java/com/hako/albumlist/widget/AlbumlistAdapter.kt +++ b/albumlist/src/main/java/com/hako/albumlist/widget/AlbumlistAdapter.kt @@ -20,7 +20,7 @@ class AlbumlistAdapter : RecyclerView.Adapter() { var onItemClick: (AlbumViewable) -> Unit = { } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = - UserViewHolder( + AlbumViewHolder( LayoutInflater .from(parent.context) .inflate(R.layout.item_album_card, parent, false), @@ -37,12 +37,12 @@ class AlbumlistAdapter : RecyclerView.Adapter() { override fun onBindViewHolder(viewholder: RecyclerView.ViewHolder, position: Int) = when (viewholder) { - is UserViewHolder -> viewholder.bind(items[position]) + is AlbumViewHolder -> viewholder.bind(items[position]) else -> throw NoWhenBranchMatchedException("Undefined viewholder") } } -class UserViewHolder(private val view: View, +class AlbumViewHolder(private val view: View, private val onItemClick: (AlbumViewable) -> Unit) : RecyclerView.ViewHolder(view) { diff --git a/albumlist/src/main/res/layout/item_album_card.xml b/albumlist/src/main/res/layout/item_album_card.xml index 162c57f..ebd8245 100644 --- a/albumlist/src/main/res/layout/item_album_card.xml +++ b/albumlist/src/main/res/layout/item_album_card.xml @@ -14,12 +14,15 @@ diff --git a/albumlist/src/main/res/navigation/albumlist_navigation.xml b/albumlist/src/main/res/navigation/albumlist_navigation.xml index 68a54ee..97da511 100644 --- a/albumlist/src/main/res/navigation/albumlist_navigation.xml +++ b/albumlist/src/main/res/navigation/albumlist_navigation.xml @@ -9,6 +9,6 @@ android:id="@+id/albumlistFragment" android:name="com.hako.albumlist.feature.AlbumlistFragment" tools:layout="@layout/fragment_albumlist" - android:label="AlbumListFragment" /> + android:label="AlbumlistFragment" /> \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3019374..feaac15 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -50,4 +50,5 @@ dependencies { implementation project(":base") implementation project(":userlist") implementation project(":albumlist") + implementation project(":photolist") } diff --git a/app/src/main/java/com/hako/friendlists/MainApplication.kt b/app/src/main/java/com/hako/friendlists/MainApplication.kt index fed3f18..14faa3d 100644 --- a/app/src/main/java/com/hako/friendlists/MainApplication.kt +++ b/app/src/main/java/com/hako/friendlists/MainApplication.kt @@ -4,6 +4,7 @@ import android.app.Application import com.hako.albumlist.di.albumListModules import com.hako.userlist.di.userlistModules import com.hako.friendlists.di.appModules +import com.hako.photolist.di.photoListModules import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin import timber.log.Timber @@ -28,7 +29,8 @@ class MainApplication : Application() { listOf( appModules, userlistModules, - albumListModules + albumListModules, + photoListModules ) ) } diff --git a/app/src/main/java/com/hako/friendlists/di/AppModules.kt b/app/src/main/java/com/hako/friendlists/di/AppModules.kt index 46b2320..98b3376 100644 --- a/app/src/main/java/com/hako/friendlists/di/AppModules.kt +++ b/app/src/main/java/com/hako/friendlists/di/AppModules.kt @@ -4,6 +4,7 @@ import androidx.room.Room import com.hako.base.domain.database.DatabaseClient import com.hako.base.domain.network.RemoteClient import com.hako.friendlists.BuildConfig +import com.squareup.picasso.Picasso import org.koin.dsl.module val appModules = module { @@ -15,4 +16,7 @@ val appModules = module { // Retrofit single { RemoteClient(BuildConfig.BASE_ENDPOINT) } + + // Picasso + single { Picasso.get() } } \ No newline at end of file diff --git a/app/src/main/res/navigation/main_navigation.xml b/app/src/main/res/navigation/main_navigation.xml index ae60acb..f235315 100644 --- a/app/src/main/res/navigation/main_navigation.xml +++ b/app/src/main/res/navigation/main_navigation.xml @@ -2,10 +2,12 @@ + app:startDestination="@id/photolist_navigation"> + + \ No newline at end of file diff --git a/base/build.gradle b/base/build.gradle index 88cc65c..440ca03 100644 --- a/base/build.gradle +++ b/base/build.gradle @@ -51,6 +51,7 @@ dependencies { api deps.okhttp_logging_interceptor api deps.timber api deps.lottie + api deps.picasso //Testing api deps.testing.junit api deps.testing.koin diff --git a/base/src/androidTest/java/com/hako/base/ExampleInstrumentedTest.kt b/base/src/androidTest/java/com/hako/base/ExampleInstrumentedTest.kt deleted file mode 100644 index c77bb07..0000000 --- a/base/src/androidTest/java/com/hako/base/ExampleInstrumentedTest.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.hako.base - -import androidx.test.platform.app.InstrumentationRegistry -import androidx.test.ext.junit.runners.AndroidJUnit4 - -import org.junit.Test -import org.junit.runner.RunWith - -import org.junit.Assert.* - -/** - * Instrumented test, which will execute on an Android device. - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -@RunWith(AndroidJUnit4::class) -class ExampleInstrumentedTest { - @Test - fun useAppContext() { - // Context of the app under test. - val appContext = InstrumentationRegistry.getInstrumentation().targetContext - assertEquals("com.hako.base.test", appContext.packageName) - } -} diff --git a/base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt b/base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt index 0fc562b..4ad3019 100644 --- a/base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt +++ b/base/src/main/java/com/hako/base/domain/database/dao/PhotoDao.kt @@ -18,6 +18,9 @@ interface PhotoDao { @get:Query("SELECT * FROM ${PhotoEntity.TABLE_NAME}") val all: List + @Query("SELECT * FROM ${PhotoEntity.TABLE_NAME} WHERE albumId = :albumId ORDER BY id ASC") + fun getPhotos(albumId: Int): List + @Query("SELECT COUNT(*) FROM ${PhotoEntity.TABLE_NAME}") fun count(): Int diff --git a/base/src/main/java/com/hako/base/domain/network/RemoteClient.kt b/base/src/main/java/com/hako/base/domain/network/RemoteClient.kt index e24863d..9d63819 100644 --- a/base/src/main/java/com/hako/base/domain/network/RemoteClient.kt +++ b/base/src/main/java/com/hako/base/domain/network/RemoteClient.kt @@ -7,6 +7,9 @@ import retrofit2.Retrofit import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory import retrofit2.converter.gson.GsonConverterFactory import timber.log.Timber +import java.util.concurrent.TimeUnit + +private const val TIMEOUT_IN_SECONDS = 60L class RemoteClient(endpoint: String) { private val logger = HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger { @@ -17,6 +20,8 @@ class RemoteClient(endpoint: String) { private val client = OkHttpClient.Builder() .addInterceptor(logger) + .readTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS) + .connectTimeout(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS) .build() private val retrofit: Retrofit = Retrofit.Builder() diff --git a/base/src/test/java/com/hako/base/ExampleUnitTest.kt b/base/src/test/java/com/hako/base/ExampleUnitTest.kt deleted file mode 100644 index e0e70a0..0000000 --- a/base/src/test/java/com/hako/base/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.hako.base - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/base/versions.gradle b/base/versions.gradle index 050b956..f001542 100644 --- a/base/versions.gradle +++ b/base/versions.gradle @@ -20,6 +20,7 @@ versions.test = "1.2.0" versions.test_ext = "1.1.1" versions.espresso = "3.2.0" versions.lottie = "3.3.1" +versions.picasso = "2.71828" def deps = [:] @@ -77,5 +78,6 @@ deps.testing = testing deps.okhttp_logging_interceptor = "com.squareup.okhttp3:logging-interceptor:$versions.okhttp_logging_interceptor" deps.timber = "com.jakewharton.timber:timber:$versions.timber" deps.lottie = "com.airbnb.android:lottie:$versions.lottie" +deps.picasso = "com.squareup.picasso:picasso:$versions.picasso" ext.deps = deps diff --git a/photolist/.gitignore b/photolist/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/photolist/.gitignore @@ -0,0 +1 @@ +/build diff --git a/photolist/build.gradle b/photolist/build.gradle new file mode 100644 index 0000000..d51b157 --- /dev/null +++ b/photolist/build.gradle @@ -0,0 +1,6 @@ +apply plugin: 'com.android.library' +apply from: '../core.gradle' + +dependencies { + implementation project(':base') +} \ No newline at end of file diff --git a/photolist/consumer-rules.pro b/photolist/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/photolist/proguard-rules.pro b/photolist/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/photolist/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/photolist/src/main/AndroidManifest.xml b/photolist/src/main/AndroidManifest.xml new file mode 100644 index 0000000..5c2fa69 --- /dev/null +++ b/photolist/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/photolist/src/main/java/com/hako/photolist/di/PhotolistModules.kt b/photolist/src/main/java/com/hako/photolist/di/PhotolistModules.kt new file mode 100644 index 0000000..41b0c45 --- /dev/null +++ b/photolist/src/main/java/com/hako/photolist/di/PhotolistModules.kt @@ -0,0 +1,15 @@ +package com.hako.photolist.di + +import com.hako.base.domain.network.RemoteClient +import com.hako.photolist.domain.datasource.PhotolistRemoteApi +import com.hako.photolist.domain.usecase.GetPhoto +import com.hako.photolist.viewmodel.PhotolistViewmodel +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.dsl.module + +val photoListModules = module { + factory { get().getClient(PhotolistRemoteApi::class.java) } + factory { GetPhoto(get()) } + + viewModel { PhotolistViewmodel() } +} \ No newline at end of file diff --git a/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotolistRemoteApi.kt b/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotolistRemoteApi.kt new file mode 100644 index 0000000..4b8ce88 --- /dev/null +++ b/photolist/src/main/java/com/hako/photolist/domain/datasource/PhotolistRemoteApi.kt @@ -0,0 +1,14 @@ +package com.hako.photolist.domain.datasource + +import com.hako.photolist.model.Photo +import io.reactivex.Single +import retrofit2.http.GET +import retrofit2.http.Query + +interface PhotolistRemoteApi { + + @GET("/photos") + fun getPhotos( + @Query("albumId") albumId: Int + ): Single> +} \ No newline at end of file diff --git a/photolist/src/main/java/com/hako/photolist/domain/usecase/GetPhoto.kt b/photolist/src/main/java/com/hako/photolist/domain/usecase/GetPhoto.kt new file mode 100644 index 0000000..9e172df --- /dev/null +++ b/photolist/src/main/java/com/hako/photolist/domain/usecase/GetPhoto.kt @@ -0,0 +1,40 @@ +package com.hako.photolist.domain.usecase + +import com.hako.base.domain.database.dao.PhotoDao +import com.hako.photolist.domain.datasource.PhotolistRemoteApi +import com.hako.photolist.model.* +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers +import org.koin.core.KoinComponent +import org.koin.core.get + +class GetPhoto(private val dao: PhotoDao) : KoinComponent { + + private val api: PhotolistRemoteApi = get() + + fun execute( + albumId: Int, + onSuccess: (List) -> Unit, + onError: (Throwable) -> Unit, + onLoading: () -> Unit + ) { + Single.fromCallable { dao.getPhotos(albumId) } + .subscribeOn(Schedulers.io()) + .doOnError { onError(it) } + .doOnSuccess { dbAlbum -> + if (dbAlbum.isEmpty() || dbAlbum.count() == 0) { + api.getPhotos(albumId) + .doOnSuccess { + dao.saveAll(it.map { album -> album.toPhotoEntity() }) + onSuccess(dao.getPhotos(albumId).map { album -> album.toPhotoViewable() }) + } + .doOnSubscribe { onLoading() } + .subscribeOn(Schedulers.io()) + .subscribe({}, { onError(it) }) + } else { + onSuccess(dbAlbum.map { it.toPhotoViewable() }) + } + } + .subscribe() + } +} diff --git a/photolist/src/main/java/com/hako/photolist/feature/PhotolistFragment.kt b/photolist/src/main/java/com/hako/photolist/feature/PhotolistFragment.kt new file mode 100644 index 0000000..9c5625a --- /dev/null +++ b/photolist/src/main/java/com/hako/photolist/feature/PhotolistFragment.kt @@ -0,0 +1,75 @@ +package com.hako.photolist.feature + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.hako.base.domain.network.RequestStatus +import com.hako.base.extensions.gone +import com.hako.base.extensions.observeNonNull +import com.hako.base.extensions.visible +import com.hako.photolist.R +import com.hako.photolist.model.PhotoViewable +import com.hako.photolist.viewmodel.PhotolistViewmodel +import com.hako.photolist.widget.PhotolistAdapter +import kotlinx.android.synthetic.main.fragment_photolist.* +import org.koin.androidx.viewmodel.ext.android.viewModel +import timber.log.Timber + +class PhotolistFragment : Fragment() { + + private val viewModel: PhotolistViewmodel by viewModel() + private val listAdapter by lazy { PhotolistAdapter() } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? + ): View = inflater.inflate(R.layout.fragment_photolist, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setRecycler() + setObservers() + // TODO: Get album by bundle + viewModel.fetchPhotos(1) + } + + private fun setObservers() { + viewModel.data.observeNonNull(this) { + it.either(::handleFetchError, ::handleFetchSuccess) + } + + viewModel.requestStatus.observeNonNull(this) { + when (it) { + RequestStatus.Ready -> { + fragment_photolist_error_overlay.gone() + fragment_photolist_loading_overlay.gone() + } + RequestStatus.Loading -> { + fragment_photolist_error_overlay.gone() + fragment_photolist_loading_overlay.visible() + } + RequestStatus.Errored -> { + fragment_photolist_error_overlay.visible() + fragment_photolist_loading_overlay.gone() + } + } + } + } + + private fun handleFetchError(throwable: Throwable) { + Timber.e(throwable) + } + + private fun handleFetchSuccess(photos: List) { + listAdapter.addAll(photos) + } + + private fun setRecycler() { + fragment_photolist_recycler_container.apply { + layoutManager = LinearLayoutManager(context) + adapter = listAdapter + } + } +} \ No newline at end of file diff --git a/photolist/src/main/java/com/hako/photolist/model/PhotoModels.kt b/photolist/src/main/java/com/hako/photolist/model/PhotoModels.kt new file mode 100644 index 0000000..14d2516 --- /dev/null +++ b/photolist/src/main/java/com/hako/photolist/model/PhotoModels.kt @@ -0,0 +1,27 @@ +package com.hako.photolist.model + +import android.os.Parcelable +import com.google.gson.annotations.SerializedName +import com.hako.base.domain.database.entities.PhotoEntity +import kotlinx.android.parcel.Parcelize + +@Parcelize +data class Photo( + @SerializedName("id") val id: Int, + @SerializedName("albumId") val albumId: Int, + @SerializedName("title") val title: String, + @SerializedName("url") val photoUrl: String, + @SerializedName("thumbnailUrl") val thumbnailUrl: String +) : Parcelable + +data class PhotoViewable( + val id: Int, + val albumId: Int, + val title: String, + val photoUrl: String +) + +fun Photo.toPhotoEntity() = PhotoEntity(this.id, this.albumId, this.title, this.photoUrl, this.thumbnailUrl) + +fun PhotoEntity.toPhotoViewable() = PhotoViewable(this.id, this.albumId, this.title, this.photoUrl) + diff --git a/photolist/src/main/java/com/hako/photolist/viewmodel/PhotolistViewmodel.kt b/photolist/src/main/java/com/hako/photolist/viewmodel/PhotolistViewmodel.kt new file mode 100644 index 0000000..3123854 --- /dev/null +++ b/photolist/src/main/java/com/hako/photolist/viewmodel/PhotolistViewmodel.kt @@ -0,0 +1,37 @@ +package com.hako.photolist.viewmodel + +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import com.hako.base.domain.network.RequestStatus +import com.hako.base.domain.network.RequestStatus.Ready +import com.hako.base.domain.network.RequestStatus.Loading +import com.hako.base.domain.network.RequestStatus.Errored +import com.hako.base.domain.Either +import com.hako.photolist.domain.usecase.GetPhoto +import com.hako.photolist.model.PhotoViewable +import org.koin.core.KoinComponent +import org.koin.core.get + +class PhotolistViewmodel : ViewModel(), KoinComponent { + + val data = MutableLiveData>>() + val requestStatus = MutableLiveData() + + private val getPhoto: GetPhoto = get() + + fun fetchPhotos(albumId: Int) { + getPhoto.execute( + albumId, + onSuccess = { + requestStatus.postValue(Ready) + data.postValue(Either.Right(it)) + }, + onLoading = { + requestStatus.postValue(Loading) + }, + onError = { + requestStatus.postValue(Errored) + data.postValue(Either.Left(it)) + }) + } +} diff --git a/photolist/src/main/java/com/hako/photolist/widget/PhotolistAdapter.kt b/photolist/src/main/java/com/hako/photolist/widget/PhotolistAdapter.kt new file mode 100644 index 0000000..66213ca --- /dev/null +++ b/photolist/src/main/java/com/hako/photolist/widget/PhotolistAdapter.kt @@ -0,0 +1,61 @@ +package com.hako.photolist.widget + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.hako.base.extensions.autoNotify +import com.hako.photolist.R +import com.hako.photolist.model.PhotoViewable +import com.squareup.picasso.Picasso +import kotlinx.android.synthetic.main.item_photo_card.view.* +import org.koin.core.KoinComponent +import org.koin.core.inject +import kotlin.properties.Delegates + +class PhotolistAdapter : RecyclerView.Adapter() { + + private var items by Delegates.observable(emptyList()) { _, oldList, newList -> + autoNotify(oldList, newList) { old, new -> old.id == new.id } + notifyDataSetChanged() + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder = + PhotoViewHolder( + LayoutInflater + .from(parent.context) + .inflate(R.layout.item_photo_card, parent, false) + ) + + fun getItem(position: Int) = items[position] + + fun addAll(list: List) { + items = list + } + + override fun getItemCount() = items.size + + override fun onBindViewHolder(viewholder: RecyclerView.ViewHolder, position: Int) = + when (viewholder) { + is PhotoViewHolder -> viewholder.bind(items[position]) + else -> throw NoWhenBranchMatchedException("Undefined viewholder") + } +} + +class PhotoViewHolder(private val view: View) : + RecyclerView.ViewHolder(view), KoinComponent { + + private val picasso: Picasso by inject() + + init { + picasso.setIndicatorsEnabled(true) + } + + fun bind(photo: PhotoViewable) = with(view) { + picasso.load(photo.photoUrl) + .placeholder(R.drawable.img_photo_placeholder) + .fit() + .into(item_photo_card_photo) + item_photo_card_title.text = photo.title + } +} \ No newline at end of file diff --git a/photolist/src/main/res/drawable/img_photo_placeholder.png b/photolist/src/main/res/drawable/img_photo_placeholder.png new file mode 100644 index 0000000..266d2fd Binary files /dev/null and b/photolist/src/main/res/drawable/img_photo_placeholder.png differ diff --git a/photolist/src/main/res/layout/fragment_photolist.xml b/photolist/src/main/res/layout/fragment_photolist.xml new file mode 100644 index 0000000..d5dfaf2 --- /dev/null +++ b/photolist/src/main/res/layout/fragment_photolist.xml @@ -0,0 +1,38 @@ + + + + + + + + + + \ No newline at end of file diff --git a/photolist/src/main/res/layout/item_photo_card.xml b/photolist/src/main/res/layout/item_photo_card.xml new file mode 100644 index 0000000..1b66e81 --- /dev/null +++ b/photolist/src/main/res/layout/item_photo_card.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/photolist/src/main/res/navigation/photolist_navigation.xml b/photolist/src/main/res/navigation/photolist_navigation.xml new file mode 100644 index 0000000..a11943a --- /dev/null +++ b/photolist/src/main/res/navigation/photolist_navigation.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/photolist/src/main/res/values/strings.xml b/photolist/src/main/res/values/strings.xml new file mode 100644 index 0000000..c6490eb --- /dev/null +++ b/photolist/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + photolist + Album photo + diff --git a/settings.gradle b/settings.gradle index 1b2d3f9..469cf91 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,2 @@ -include ':app', ':base', ':userlist', ':albumlist' +include ':app', ':base', ':userlist', ':albumlist', ':photolist' rootProject.name='Friendlists' diff --git a/userlist/src/main/res/navigation/userlist_navigation.xml b/userlist/src/main/res/navigation/userlist_navigation.xml index 20c9258..db70b2f 100644 --- a/userlist/src/main/res/navigation/userlist_navigation.xml +++ b/userlist/src/main/res/navigation/userlist_navigation.xml @@ -3,12 +3,12 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/userlist_navigation" - app:startDestination="@id/userListFragment"> + app:startDestination="@id/userlistFragment"> + android:label="UserlistFragment" /> \ No newline at end of file