Skip to content

Commit

Permalink
Merge pull request #39 from SoftwareEngineeringDaily/develop
Browse files Browse the repository at this point in the history
v1.0.3
  • Loading branch information
MostafaGazar authored Nov 12, 2019
2 parents 7828dd2 + ac1e0c2 commit f3be5b5
Show file tree
Hide file tree
Showing 21 changed files with 213 additions and 60 deletions.
6 changes: 6 additions & 0 deletions .stickler.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
linters:
ktlint:
android: true
fixer: true
fixers:
enable: true
7 changes: 5 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ android {
applicationId "com.koalatea.sedaily"
minSdkVersion 21
targetSdkVersion 29
versionCode 18
versionName "1.0.2"
versionCode 19
versionName "1.0.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

Expand Down Expand Up @@ -141,6 +141,9 @@ dependencies {
// Timber
implementation 'com.jakewharton.timber:timber:4.7.1'

// Custom Tabs
implementation 'androidx.browser:browser:1.0.0'

// Testing
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ data class Comment(
val author: Author,
val rootEntity: String,
val content: String,
val mentions: List<String>?,
val deleted: Boolean?,
val dateCreated: String,
val score: Int?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class BookmarksFragment : BaseFragment() {
epoxyRecyclerView.setController(this)
}

bookmarksSwipeRefreshLayout.setOnRefreshListener {
viewModel.fetchBookmarks()
}

viewModel.bookmarksResource.observe(this, Observer { resource ->
when (resource) {
is Resource.Loading -> {
Expand Down Expand Up @@ -94,18 +98,18 @@ class BookmarksFragment : BaseFragment() {

private fun showLoading() {
emptyStateContainer.visibility = View.GONE
epoxyRecyclerView.visibility = View.GONE
bookmarksSwipeRefreshLayout.visibility = View.GONE

progressBar.visibility = View.VISIBLE
bookmarksSwipeRefreshLayout.isRefreshing = true
}

private fun hideLoading() {
progressBar.visibility = View.GONE
bookmarksSwipeRefreshLayout.isRefreshing = false
}

private fun showLoginEmptyState() {
epoxyRecyclerView.visibility = View.GONE
progressBar.visibility = View.GONE
bookmarksSwipeRefreshLayout.visibility = View.GONE
bookmarksSwipeRefreshLayout.isRefreshing = false

emptyStateContainer.textView.text = getString(R.string.login_to_manage_bookmarks)
emptyStateContainer.visibility = View.VISIBLE
Expand All @@ -115,9 +119,9 @@ class BookmarksFragment : BaseFragment() {
bookmarksEpoxyController?.setData(episodes)

emptyStateContainer.visibility = View.GONE
progressBar.visibility = View.GONE
bookmarksSwipeRefreshLayout.isRefreshing = false

epoxyRecyclerView.visibility = View.VISIBLE
bookmarksSwipeRefreshLayout.visibility = View.VISIBLE
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class CommentsFragment : BaseFragment() {
commentsEpoxyController = CommentsEpoxyController(
replyClickListener = { comment ->
viewModel.replyTo(comment)
},
upVoteClickListener = { comment ->
viewModel.upVoteComment(comment)
}
).apply {
epoxyRecyclerView.setController(this)
Expand All @@ -73,6 +76,21 @@ class CommentsFragment : BaseFragment() {
viewModel.cancelReply()
}

viewModel.commentVoteLiveData.observe(this, Observer { it.getContentIfNotHandled()?.let { resource ->
when (resource) {
is Resource.RequireLogin -> showPromptLoginDialog()
is Resource.Success -> {
viewModel.reloadComments(entityId)
}
is Resource.Error -> {
hideLoading()

if (resource.isConnected) acknowledgeGenericError() else acknowledgeConnectionError()
}
}
}
})

viewModel.commentsResource.observe(this, Observer { resource ->
when (resource) {
is Resource.Loading -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class CommentsViewModel(
val replyToCommentLiveData: LiveData<Comment?>
get() = _replyToCommentLiveData

private val _commentVoteLiveData = MutableLiveData<Event<Resource<Boolean>>>()
val commentVoteLiveData: LiveData<Event<Resource<Boolean>>>
get() = _commentVoteLiveData

private val _addCommentLiveData = MutableLiveData<Event<Resource<Boolean>>>()
val addCommentLiveData: LiveData<Event<Resource<Boolean>>>
get() = _addCommentLiveData
Expand All @@ -42,6 +46,16 @@ class CommentsViewModel(
entityIdLiveData.value = entityId
}

@MainThread
fun upVoteComment(comment: Comment) = viewModelScope.launch {
with(_commentVoteLiveData) {
postValue(Event(Resource.Loading))

val resource = commentsRepository.upVoteComment(comment._id)
postValue(Event(resource))
}
}

@MainThread
fun addComment(comment: String) = viewModelScope.launch {
if (comment.isBlank()) return@launch
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ abstract class BaseCommentEpoxyModelWithHolder<Holder: BaseCommentHolder> : Epox
@EpoxyAttribute lateinit var authorName: String
@EpoxyAttribute lateinit var comment: String
@EpoxyAttribute var date: Date? = null
@EpoxyAttribute var score: Int? = 0
@EpoxyAttribute var upvoted: Boolean = false

@CallSuper
override fun bind(holder: Holder) {
Expand All @@ -43,7 +45,6 @@ abstract class BaseCommentEpoxyModelWithHolder<Holder: BaseCommentHolder> : Epox
holder.dateTextView.visibility = View.GONE
}
}

}

abstract class BaseCommentHolder : KotlinEpoxyHolder() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@ import com.koalatea.sedaily.R
abstract class CommentEpoxyModelWithHolder : BaseCommentEpoxyModelWithHolder<CommentHolder>() {

@EpoxyAttribute lateinit var replyClickListener: () -> Unit
@EpoxyAttribute lateinit var upVoteClickListener: () -> Unit

override fun bind(holder: CommentHolder) {
super.bind(holder)

holder.replayButton.setOnClickListener { replyClickListener() }
holder.upVoteButton.setOnClickListener { upVoteClickListener() }
holder.upVoteButton.isSelected = upvoted
holder.upVoteButton.text = score?.let {
if (it > 0) { it.toString() } else { "" }
} ?: ""
}

}

class CommentHolder : BaseCommentHolder() {
val replayButton by bind<Button>(R.id.replyButton)
}
val upVoteButton by bind<Button>(R.id.commentUpvoteButton)
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import com.airbnb.epoxy.TypedEpoxyController
import com.koalatea.sedaily.database.model.Comment

class CommentsEpoxyController(
private val replyClickListener: (comment: Comment) -> Unit
private val replyClickListener: (comment: Comment) -> Unit,
private val upVoteClickListener: (comment: Comment) -> Unit
) : TypedEpoxyController<List<Comment>>() {

override fun buildModels(comments: List<Comment>) {
Expand All @@ -17,7 +18,10 @@ class CommentsEpoxyController(
authorName(comment.author.name ?: comment.author.username)
comment(comment.content)
date(comment.utcDateCreated)
score(comment.score)
replyClickListener { replyClickListener(comment) }
upVoteClickListener { upVoteClickListener(comment) }
upvoted(comment?.upvoted ?: false)
}

comment.replies?.forEach { reply ->
Expand All @@ -29,9 +33,12 @@ class CommentsEpoxyController(
authorName(reply.author.name ?: comment.author.username)
comment(reply.content)
date(reply.utcDateCreated)
upVoteClickListener { upVoteClickListener(reply) }
upvoted(reply?.upvoted ?: false)
score(reply.score)
}
}
}
}

}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
package com.koalatea.sedaily.feature.commentList.epoxy

import android.widget.Button
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import com.koalatea.sedaily.R

@EpoxyModelClass(layout = R.layout.view_holder_reply)
abstract class ReplyEpoxyModelWithHolder : BaseCommentEpoxyModelWithHolder<ReplyHolder>()
abstract class ReplyEpoxyModelWithHolder : BaseCommentEpoxyModelWithHolder<ReplyHolder>() {

class ReplyHolder : BaseCommentHolder()
@EpoxyAttribute lateinit var upVoteClickListener: () -> Unit

override fun bind(holder: ReplyHolder) {
super.bind(holder)

holder.upVoteButton.setOnClickListener { upVoteClickListener() }
holder.upVoteButton.isSelected = upvoted
holder.upVoteButton.text = score?.let {
if (it > 0) { it.toString() } else { "" }
} ?: ""
}
}

class ReplyHolder : BaseCommentHolder() {
val upVoteButton by bind<Button>(R.id.replyUpvoteButton)
}
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,8 @@ class EpisodeDetailFragment : BaseFragment() {
}

private fun renderPlay(episode: Episode) {
// Playback is not supported
if (playerCallback == null) {
// Playback is not supported or viewing an article
if (playerCallback == null || episode.httpsMp3Url.isNullOrBlank()) {
hidePlayerViews()
} else {
monitorPlayback(episode)
Expand All @@ -313,6 +313,13 @@ class EpisodeDetailFragment : BaseFragment() {
playerCallback?.playerStatusLiveData?.removeObservers(this)
}
}

// Cannot download or view related links for an article
if (episode.httpsMp3Url.isNullOrBlank()) {
hideDownloadViews()

relatedLinksButton.visibility = View.INVISIBLE
}
}

private fun monitorPlayback(episode: Episode) {
Expand All @@ -337,6 +344,12 @@ class EpisodeDetailFragment : BaseFragment() {
downloadProgressBar.visibility = View.INVISIBLE
}

private fun hideDownloadViews() {
deleteButton.visibility = View.GONE
downloadButton.visibility = View.INVISIBLE
downloadProgressBar.visibility = View.INVISIBLE
}

private fun showDeleteViews() {
deleteButton.visibility = View.VISIBLE
downloadButton.visibility = View.INVISIBLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
import timber.log.Timber
import java.util.*

private const val PLAYBACK_CHANNEL_ID = "playback_channel"
Expand Down Expand Up @@ -100,14 +101,6 @@ class AudioService : LifecycleService() {
val playerStatusLiveData: LiveData<PlayerStatus>
get() = _playerStatusLiveData

override fun onBind(intent: Intent?): IBinder {
super.onBind(intent)

handleIntent(intent)

return AudioServiceBinder()
}

override fun onCreate() {
super.onCreate()

Expand Down Expand Up @@ -213,6 +206,14 @@ class AudioService : LifecycleService() {
}
}

override fun onBind(intent: Intent?): IBinder {
super.onBind(intent)

handleIntent(intent)

return AudioServiceBinder()
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
handleIntent(intent)

Expand All @@ -233,17 +234,16 @@ class AudioService : LifecycleService() {

@MainThread
private fun handleIntent(intent: Intent?) {
episodeId = intent?.getStringExtra(ARG_EPISODE_ID)
episodeTitle = intent?.getStringExtra(ARG_TITLE)

// Play
intent?.let {
intent.getParcelableExtra<Uri>(ARG_URI)?.also { uri ->
episodeId = intent.getStringExtra(ARG_EPISODE_ID)
episodeTitle = intent.getStringExtra(ARG_TITLE)
val startPosition = intent.getLongExtra(ARG_START_POSITION, C.POSITION_UNSET.toLong())
val playbackSpeed = playbackManager.playbackSpeed

play(uri, startPosition, playbackSpeed)
}
} ?: Timber.w("Playback uri was not set")
}
}

Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/com/koalatea/sedaily/network/SEDailyApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ interface SEDailyApi {
@GET("comments/forEntity/{entity_id}")
fun getEpisodeCommentsAsync(@Path("entity_id") entityId: String): Deferred<Response<CommentsResponse>>

@POST("comments/{entity_id}/upvote")
fun upVoteCommentsAsync(@Path("entity_id") entityId: String): Deferred<Response<GenericResponse>>

@FormUrlEncoded
@POST("comments/forEntity/{entity_id}")
fun addEpisodeCommentAsync(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,16 @@ class CommentsRepository(
}
}

}
suspend fun upVoteComment(entityId: String) = withContext(Dispatchers.IO) {
if (sessionRepository.isLoggedIn) {
val response = safeApiCall { api.upVoteCommentsAsync(entityId).await() }
if (response?.isSuccessful == true) {
Resource.Success(true)
} else {
Resource.Error(response?.errorBody().toException(), networkManager.isConnected)
}
} else {
Resource.RequireLogin
}
}
}
Loading

0 comments on commit f3be5b5

Please sign in to comment.