Skip to content

Commit

Permalink
Merge pull request #86 from itszechs/feature-mark-as-star
Browse files Browse the repository at this point in the history
Feature mark as star
  • Loading branch information
itszechs authored Feb 7, 2023
2 parents 3b4edd5 + b26bb34 commit 523dcb6
Show file tree
Hide file tree
Showing 14 changed files with 258 additions and 11 deletions.
3 changes: 2 additions & 1 deletion app/src/main/java/zechs/drive/stream/data/model/DriveFile.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ data class DriveFile(
val size: Long?,
val mimeType: String,
val iconLink: String?,
val shortcutDetails: ShortcutDetails
val shortcutDetails: ShortcutDetails,
val starred: Starred
) {
val humanSize = size?.let { Converter.toHumanSize(it) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ data class Drive(
size = null,
mimeType = kind,
iconLink = null,
shortcutDetails = ShortcutDetails()
shortcutDetails = ShortcutDetails(),
starred = Starred.UNKNOWN
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package zechs.drive.stream.data.model

import androidx.annotation.Keep

@Keep
data class FileUpdateRequest(
val starred: Boolean
)
28 changes: 26 additions & 2 deletions app/src/main/java/zechs/drive/stream/data/model/FilesResponse.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package zechs.drive.stream.data.model

import androidx.annotation.Keep
import com.squareup.moshi.FromJson
import com.squareup.moshi.Json
import com.squareup.moshi.ToJson

@Keep
data class FilesResponse(
Expand All @@ -15,13 +18,34 @@ data class File(
val size: Long?,
val iconLink: String,
val mimeType: String,
val shortcutDetails: ShortcutDetails = ShortcutDetails()
val shortcutDetails: ShortcutDetails = ShortcutDetails(),
@Json(name = "starred")
val starred: Starred
) {
fun toDriveFile() = DriveFile(id, name, size, mimeType, iconLink, shortcutDetails)
fun toDriveFile() = DriveFile(id, name, size, mimeType, iconLink, shortcutDetails, starred)
}

@Keep
data class ShortcutDetails(
val targetId: String? = null,
val targetMimeType: String? = null
)

enum class Starred {
UNSTARRED, STARRED, UNKNOWN, LOADING
}


class StarredAdapter {

@FromJson
fun fromJson(starred: Boolean): Starred {
return if (starred) Starred.STARRED else Starred.UNSTARRED
}

@ToJson
fun toJson(starred: Starred): Boolean {
return starred == Starred.STARRED
}

}
21 changes: 17 additions & 4 deletions app/src/main/java/zechs/drive/stream/data/remote/DriveApi.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package zechs.drive.stream.data.remote

import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.Query
import retrofit2.Response
import retrofit2.http.*
import zechs.drive.stream.data.model.DriveResponse
import zechs.drive.stream.data.model.FileUpdateRequest
import zechs.drive.stream.data.model.FilesResponse

interface DriveApi {
Expand All @@ -21,7 +21,7 @@ interface DriveApi {
@Query("pageToken")
pageToken: String? = null,
@Query("fields")
fields: String = "nextPageToken, files(id, name, size, mimeType, iconLink, shortcutDetails)",
fields: String = "nextPageToken, files(id, name, size, mimeType, iconLink, shortcutDetails, starred)",
@Query("orderBy")
orderBy: String = "folder, name",
@Query("q")
Expand All @@ -40,4 +40,17 @@ interface DriveApi {
fields: String = "nextPageToken, drives(id, name, kind)"
): DriveResponse

@PATCH("/drive/v3/files/{fileId}")
suspend fun updateFile(
@Header("Authorization")
accessToken: String,
@Path("fileId")
fileId: String,
@Query("supportsAllDrives")
supportsAllDrives: Boolean = true,
@Query("includeItemsFromAllDrives")
includeItemsFromAllDrives: Boolean = true,
@Body fileUpdateRequest: FileUpdateRequest
): Response<Unit>

}
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,26 @@ class DriveRepository @Inject constructor(
return Resource.Error(error)
}

suspend fun updateFile(
fileId: String,
starred: Boolean
): Resource<Unit> {
val tokenResponse = sessionManager.fetchAccessToken()
?: return Resource.Error("Access token can not be null")
return try {
val update = driveApi.updateFile(
fileId = fileId,
fileUpdateRequest = FileUpdateRequest(starred = starred),
accessToken = "Bearer ${tokenResponse.accessToken}"
)
if (update.isSuccessful) {
Resource.Success(Unit)
} else {
Resource.Error("Failed to update")
}
} catch (e: Exception) {
doOnError(e)
}
}

}
2 changes: 2 additions & 0 deletions app/src/main/java/zechs/drive/stream/di/ApiModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import zechs.drive.stream.BuildConfig
import zechs.drive.stream.data.model.StarredAdapter
import zechs.drive.stream.data.remote.DriveApi
import zechs.drive.stream.data.remote.GithubApi
import zechs.drive.stream.data.remote.TokenApi
Expand Down Expand Up @@ -81,6 +82,7 @@ object ApiModule {
@Singleton
fun provideMoshi(): Moshi {
return Moshi.Builder()
.add(StarredAdapter())
.add(KotlinJsonAdapterFactory())
.build()
}
Expand Down
20 changes: 19 additions & 1 deletion app/src/main/java/zechs/drive/stream/ui/files/FilesFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import android.widget.TextView
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DividerItemDecoration
Expand Down Expand Up @@ -89,6 +91,16 @@ class FilesFragment : BaseFragment() {
setupRecyclerView()
setupFilesObserver()
mpvObserver()

viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.fileUpdate.collect { status ->
showSnackBar(status)
}
}
}


}

private fun setupFilesObserver() {
Expand Down Expand Up @@ -125,6 +137,7 @@ class FilesFragment : BaseFragment() {
}

private fun onSuccess(files: List<FilesDataModel>) {
Log.d(TAG, "onSuccess(files=${files.size})")
if (!viewModel.hasLoaded) {
doTransition(MaterialFadeThrough())
}
Expand Down Expand Up @@ -183,7 +196,12 @@ class FilesFragment : BaseFragment() {
}

private val filesAdapter by lazy {
FilesAdapter(onClickListener = { handleFileOnClick(it) })
FilesAdapter(
onClickListener = { handleFileOnClick(it) },
onStarClickListener = { file, isStarred ->
viewModel.starFile(file, isStarred)
}
)
}

private fun handleFileOnClick(file: DriveFile) {
Expand Down
63 changes: 63 additions & 0 deletions app/src/main/java/zechs/drive/stream/ui/files/FilesViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import zechs.drive.stream.data.model.DriveFile
import zechs.drive.stream.data.model.Starred
import zechs.drive.stream.data.repository.DriveRepository
import zechs.drive.stream.ui.files.FilesFragment.Companion.TAG
import zechs.drive.stream.ui.files.adapter.FilesDataModel
Expand Down Expand Up @@ -192,4 +196,63 @@ class FilesViewModel @Inject constructor(
}
}

private val _fileUpdate = MutableSharedFlow<String>()
val fileUpdate: SharedFlow<String>
get() = _fileUpdate.asSharedFlow()

fun starFile(
file: DriveFile,
starred: Boolean
) = viewModelScope.launch(Dispatchers.IO) {
fun updateFileState(starredStarred: Starred) {
response?.indexOfFirst {
if (it is FilesDataModel.File) {
it.driveFile.id == file.id
} else false
}?.let { index ->
if (index != -1) {
val newFile = FilesDataModel.File(
file.copy(starred = starredStarred)
)
response!![index] = newFile
_filesList.postValue(Resource.Success(response!!))
}
}
}

try {
updateFileState(Starred.LOADING)

val update = driveRepository.updateFile(
fileId = file.id,
starred = starred
)
when (update) {
is Resource.Error -> {
_fileUpdate.emit(update.message!!)
updateFileState(if (starred) Starred.UNSTARRED else Starred.STARRED)
}
is Resource.Success -> {
Log.d(TAG, "File updated")
updateFileState(
if (starred) Starred.STARRED else Starred.UNSTARRED
)
}
else -> {}
}
} catch (cancel: CancellationException) {
updateFileState(if (starred) Starred.UNSTARRED else Starred.STARRED)
_fileUpdate.emit("Unable to update file")
Log.d(TAG, cancel.message ?: "CancellationException")
} catch (timeout: SocketTimeoutException) {
updateFileState(if (starred) Starred.UNSTARRED else Starred.STARRED)
_fileUpdate.emit("Server timed out")
Log.d(TAG, timeout.message ?: "SocketTimeoutException")
} catch (e: Exception) {
updateFileState(if (starred) Starred.UNSTARRED else Starred.STARRED)
_fileUpdate.emit(e.message ?: "Something went wrong")
Log.e(TAG, "Something went wrong", e)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import zechs.drive.stream.databinding.ItemDriveFileBinding
import zechs.drive.stream.databinding.ItemLoadingBinding

class FilesAdapter(
val onClickListener: (DriveFile) -> Unit
val onClickListener: (DriveFile) -> Unit,
val onStarClickListener: (DriveFile, Boolean) -> Unit
) : ListAdapter<FilesDataModel, FilesViewHolder>(FilesItemDiffCallback()) {

override fun onCreateViewHolder(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package zechs.drive.stream.ui.files.adapter

import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import com.bumptech.glide.request.RequestOptions
import zechs.drive.stream.R
import zechs.drive.stream.data.model.DriveFile
import zechs.drive.stream.data.model.Starred
import zechs.drive.stream.databinding.ItemDriveFileBinding
import zechs.drive.stream.databinding.ItemLoadingBinding
import zechs.drive.stream.utils.GlideApp
Expand All @@ -19,6 +22,43 @@ sealed class FilesViewHolder(
val filesAdapter: FilesAdapter
) : FilesViewHolder(itemBinding) {

private fun setStarred(file: DriveFile, starredState: Starred) {
when (starredState) {
Starred.UNSTARRED -> {
itemBinding.apply {
btnStar.isInvisible = false
starLoading.isGone = true
btnStar.setImageResource(R.drawable.ic_star_round_24)
btnStar.setOnClickListener {
filesAdapter.onStarClickListener.invoke(file, true)
}
}
}
Starred.STARRED -> {
itemBinding.apply {
btnStar.isInvisible = false
starLoading.isGone = true
btnStar.setImageResource(R.drawable.ic_starred_round_24)
btnStar.setOnClickListener {
filesAdapter.onStarClickListener.invoke(file, false)
}
}
}
Starred.LOADING -> {
itemBinding.apply {
btnStar.isInvisible = true
starLoading.isGone = false
}
}
Starred.UNKNOWN -> {
itemBinding.apply {
btnStar.isGone = true
starLoading.isGone = true
}
}
}
}

fun bind(file: FilesDataModel.File) {
val item = file.driveFile
itemBinding.apply {
Expand Down Expand Up @@ -47,6 +87,7 @@ sealed class FilesViewHolder(
filesAdapter.onClickListener.invoke(item)
}

setStarred(item, item.starred)
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_star_round_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M19.65,9.04l-4.84,-0.42 -1.89,-4.45c-0.34,-0.81 -1.5,-0.81 -1.84,0L9.19,8.63l-4.83,0.41c-0.88,0.07 -1.24,1.17 -0.57,1.75l3.67,3.18 -1.1,4.72c-0.2,0.86 0.73,1.54 1.49,1.08l4.15,-2.5 4.15,2.51c0.76,0.46 1.69,-0.22 1.49,-1.08l-1.1,-4.73 3.67,-3.18c0.67,-0.58 0.32,-1.68 -0.56,-1.75zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z" />
</vector>
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/ic_starred_round_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12,17.27l4.15,2.51c0.76,0.46 1.69,-0.22 1.49,-1.08l-1.1,-4.72l3.67,-3.18c0.67,-0.58 0.31,-1.68 -0.57,-1.75l-4.83,-0.41l-1.89,-4.46c-0.34,-0.81 -1.5,-0.81 -1.84,0L9.19,8.63L4.36,9.04c-0.88,0.07 -1.24,1.17 -0.57,1.75l3.67,3.18l-1.1,4.72c-0.2,0.86 0.73,1.54 1.49,1.08L12,17.27z" />
</vector>
Loading

0 comments on commit 523dcb6

Please sign in to comment.