Skip to content

Commit

Permalink
now stores all daily trend found on a page
Browse files Browse the repository at this point in the history
Trend page displays 7 days of trends
closes #214
  • Loading branch information
yudanhezhongweijie committed Feb 28, 2021
1 parent e79a2d7 commit 3e157f6
Show file tree
Hide file tree
Showing 16 changed files with 192 additions and 120 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# ChangeLog 更新日志
- 1.3.52
- 查看一周热榜

- 1.3.51
- 添加跑团灌铅
- bug修复

- 1.3.50
- 添加查看总版规按钮
- 修复热榜
Expand Down
16 changes: 8 additions & 8 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ android {
applicationId "com.laotoua.dawnislandk"
minSdkVersion 23
targetSdkVersion 29
versionCode 44
versionName "v1.3.51"
versionCode 45
versionName "v1.3.52"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down Expand Up @@ -125,17 +125,17 @@ dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'

implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation "androidx.activity:activity-ktx:1.2.0-rc01"
implementation "androidx.fragment:fragment-ktx:1.3.0-rc01"
implementation "androidx.activity:activity-ktx:1.3.0-alpha03"
implementation "androidx.fragment:fragment-ktx:1.3.0"

def lifecycle_version = "2.3.0-rc01"
def lifecycle_version = "2.3.0"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"


implementation 'com.google.android.material:material:1.3.0-rc01'
implementation 'com.google.android.material:material:1.4.0-alpha01'

def appcompat_version = "1.3.0-beta01"
implementation "androidx.appcompat:appcompat:$appcompat_version"
Expand All @@ -154,7 +154,7 @@ dependencies {

implementation 'org.jsoup:jsoup:1.13.1'
implementation 'org.apache.commons:commons-text:1.9'
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6'

implementation 'com.lxj:xpopup:2.2.14'
// implementation project(path: ':XPopup') //##localized @ 2.1.7
Expand Down Expand Up @@ -191,7 +191,7 @@ dependencies {
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"

def nav_version = "2.3.2"
def nav_version = "2.3.3"
// Kotlin navigation
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
Expand Down
4 changes: 2 additions & 2 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
#-renamesourcefileattribute SourceFile

# xPopup
#-dontwarn com.lxj.xpopup.widget.**
#-keep class com.lxj.xpopup.widget.**{*;}
-dontwarn com.lxj.xpopup.widget.**
-keep class com.lxj.xpopup.widget.**{*;}

# https://issuetracker.google.com/issues/142601969
-keepnames class androidx.navigation.fragment.NavHostFragment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,20 @@ interface DailyTrendDao {
@Query("SELECT * FROM DailyTrend")
suspend fun getAll(): List<DailyTrend>

@Query("SELECT * FROM DailyTrend ORDER BY id DESC LIMIT 1")
suspend fun findLatestDailyTrendSync(): DailyTrend?
@Query("SELECT * FROM DailyTrend ORDER BY id DESC LIMIT 7")
suspend fun findLatestDailyTrendsSync(): List<DailyTrend>

@Query("SELECT * FROM DailyTrend ORDER BY id DESC LIMIT 1")
fun findLatestDailyTrend(): LiveData<DailyTrend>
@Query("SELECT * FROM DailyTrend ORDER BY id DESC LIMIT 7")
fun findLatestDailyTrends(): LiveData<List<DailyTrend>>

fun findDistinctLatestDailyTrend(): LiveData<DailyTrend> = findLatestDailyTrend().distinctUntilChanged()
fun findDistinctLatestDailyTrends(): LiveData<List<DailyTrend>> = findLatestDailyTrends().distinctUntilChanged()

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(dailyTrend: DailyTrend)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(dailyTrends: List<DailyTrend>)

@Delete
suspend fun delete(dailyTrend: DailyTrend)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.room.Entity
import androidx.room.PrimaryKey
import com.squareup.moshi.JsonClass
import java.time.LocalDateTime
import kotlin.math.ceil

@JsonClass(generateAdapter = true)
@Entity
Expand All @@ -34,6 +35,8 @@ data class DailyTrend(
@PrimaryKey(autoGenerate = true)
var id: Int = 0

val page: Int get() = ceil(lastReplyCount.toDouble() / 19).toInt()

override fun equals(other: Any?): Boolean =
if (other is DailyTrend) {
po == other.po && date.toLocalDate().isEqual(other.date.toLocalDate()) && postId == other.postId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ data class Post(
val admin: String = "0",//admin 是否是酷炫红名,如果是酷炫红名则userid为红名id
val status: String = "",
@Json(name = "replys") @Ignore var comments: List<Comment> = emptyList(), //replys 主页展示回复的帖子(5个)
val replyCount: String = "",
val replyCount: String = "0",
var lastUpdatedAt: LocalDateTime = LocalDateTime.now()
) {
// Room uses this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ class FeedRepository @Inject constructor(
)
}
}

}

// Note only return request status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,29 @@
package com.laotoua.dawnislandk.data.repository

import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.liveData
import com.laotoua.dawnislandk.DawnApp
import com.laotoua.dawnislandk.data.local.dao.DailyTrendDao
import com.laotoua.dawnislandk.data.local.entity.DailyTrend
import com.laotoua.dawnislandk.data.local.entity.FeedAndPost
import com.laotoua.dawnislandk.data.local.entity.Post
import com.laotoua.dawnislandk.data.local.entity.Trend
import com.laotoua.dawnislandk.data.remote.APIDataResponse
import com.laotoua.dawnislandk.data.remote.NMBServiceClient
import com.laotoua.dawnislandk.util.DataResource
import com.laotoua.dawnislandk.util.LoadingStatus
import com.laotoua.dawnislandk.util.ReadableTime
import com.laotoua.dawnislandk.util.getLocalListDataResource
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
import java.time.LocalDateTime
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.ceil
import kotlin.math.max


@Singleton
Expand All @@ -47,40 +53,70 @@ class TrendRepository @Inject constructor(
private val trendDelimiter = "\n\u2014\u2014\u2014\u2014\u2014<br />\n<br />\n"

private val trendLength = 32
private var cache: DailyTrend? = null

private var _maxPage = 1
val maxPage: Int get() = _maxPage
val latestTrends = MediatorLiveData<DataResource<List<DailyTrend>>>()
private val cache: LiveData<DataResource<List<DailyTrend>>> = getLocalListDataResource(dailyTrendDao.findDistinctLatestDailyTrends())
private lateinit var remote: LiveData<DataResource<List<DailyTrend>>>
private var trendsCount = 0

// Remote only acts as a request status responder, actual data will be emitted by local cache
fun getLatestTrend(): LiveData<DataResource<DailyTrend>> = liveData {
var getRemoteData = true
if (cache == null) cache = dailyTrendDao.findLatestDailyTrendSync()
cache?.let {
emit(DataResource.create(LoadingStatus.SUCCESS, it))
_maxPage = ceil(it.lastReplyCount.toDouble() / 19).toInt()
// trends updates daily at 1AM, allows 24 hour CD
if (ReadableTime.serverDateTimeToUserLocalDateTime(it.date).plusDays(1).isAfter(LocalDateTime.now())) {
getRemoteData = false

var maxPage = 1
private set

init {
subscribeToCache()
}


private fun subscribeToCache() {
latestTrends.addSource(cache) {
if (it.status == LoadingStatus.SUCCESS && trendsCount > 0 && trendsCount < 7){
latestTrends.value = DataResource.create(data = it.data)
} else if (it.status == LoadingStatus.SUCCESS) {
latestTrends.value = it
}
maxPage = it.data?.first()?.page ?: 1
subscribeToRemote()
}
}


fun subscribeToRemote() {
if (this::remote.isInitialized) latestTrends.removeSource(remote)
remote = liveData<DataResource<List<DailyTrend>>> {
val lastDate: LocalDateTime? = cache.value?.data?.firstOrNull()?.date
if (lastDate != null && ReadableTime.serverDateTimeToUserLocalDateTime(lastDate).plusDays(1).isAfter(LocalDateTime.now())) {
Timber.d("It's less than 24 hours since Trend last updated. Reusing...")
emit(DataResource.create(LoadingStatus.SUCCESS, cache.value?.data))
} else {
trendsCount = 0
emit(DataResource.create())
val result = getRemoteTrend(maxPage)
emit(result)
}
}
if (getRemoteData) {
emit(DataResource.create())
getRemoteTrend(_maxPage)?.let { emit(it) }
latestTrends.addSource(remote) {
latestTrends.value = DataResource.create(it.status, cache.value?.data, it.message)
}
}

private suspend fun getRemoteTrend(page: Int): DataResource<DailyTrend>? {
Timber.d("Getting remote trend on page $page")
// Remote only acts as a request status responder, actual data will be emitted by local cache
private suspend fun getRemoteTrend(page: Int): DataResource<List<DailyTrend>> {
Timber.d("Getting remote trends on page $page")
return webService.getComments(trendId, page).run {
if (this is APIDataResponse.Success) {
val targetPage = ceil(data!!.replyCount.toDouble() / 19).toInt()
if (targetPage != _maxPage) {
_maxPage = targetPage
getRemoteTrend(targetPage)
val newMaxPage = ceil(data!!.replyCount.toDouble() / 19).toInt()
if (maxPage < newMaxPage) {
maxPage = newMaxPage
extractLatestTrends(data)
getRemoteTrend(newMaxPage)
} else {
convertLatestTrend(targetPage, data)
trendsCount += extractLatestTrends(data)
if (trendsCount < 7) {
Timber.d("Only got $trendsCount/7 Daily Trend from last Page. Need more...")
getRemoteTrend(page - 1)
}
else DataResource.create(LoadingStatus.SUCCESS, emptyList())
}
} else {
Timber.e(message)
Expand All @@ -89,49 +125,36 @@ class TrendRepository @Inject constructor(
}
}

private suspend fun convertLatestTrend(targetPage: Int, data: Post): DataResource<DailyTrend>? {
var newDailyTrend: DailyTrend? = null
for (reply in data.comments.reversed()) {
suspend fun extractLatestTrends(data: Post): Int {
val foundTrends = mutableListOf<DailyTrend>()
for (reply in data.comments) {
if (reply.userid == po) {
val content = if (reply.content.startsWith("@")) reply.content.substringAfter("<br />\n")
else reply.content
val content = if (reply.content.startsWith("@")) reply.content.substringAfter("<br />\n") else reply.content
val list = content.split(trendDelimiter, ignoreCase = true)
if (list.size == trendLength) {
try {
newDailyTrend = DailyTrend(
val newDailyTrend = DailyTrend(
reply.id,
reply.userid,
ReadableTime.serverTimeStringToServerLocalDateTime(reply.now),
list.map { convertStringToTrend(it) },
data.replyCount.toInt()
)
break
foundTrends.add(newDailyTrend)
} catch (e: Exception) {
Timber.e(e)
return DataResource.create(LoadingStatus.ERROR, null, "无法读取热榜,请尝试更新版本或者联系开发者")
}
}
}
}

return when {
newDailyTrend != null -> {
if (cache == null || !newDailyTrend.date.toLocalDate().isEqual(cache!!.date.toLocalDate())) {
Timber.d("Found new trends. Saving...")
cache = newDailyTrend
coroutineScope { launch { dailyTrendDao.insert(newDailyTrend) } }
}
DataResource.create(LoadingStatus.SUCCESS, newDailyTrend)
}
targetPage - 1 > 1 -> {
getRemoteTrend(targetPage - 1)
}
else -> {
DataResource.create(LoadingStatus.ERROR, null, "无法读取热榜,请尝试更新版本或者联系开发者")
}
if (foundTrends.isNotEmpty()) {
Timber.d("Found ${foundTrends.size} Daily Trend. Saving...")
coroutineScope { launch { dailyTrendDao.insertAll(foundTrends) } }
}
return foundTrends.size
}


/**
* sample
* 01. Trend 367 [欢乐恶搞] <br />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ class MainActivity : DaggerAppCompatActivity() {
}
}
} catch (e: Exception) {
Timber.e("$url test failed with $e")
Timber.e("$url Host Test failed with $e")
} finally {
connection?.disconnect()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import com.laotoua.dawnislandk.R
import com.laotoua.dawnislandk.data.local.entity.Comment
import com.laotoua.dawnislandk.data.local.entity.Emoji
import com.laotoua.dawnislandk.data.local.entity.Post
import com.laotoua.dawnislandk.data.local.entity.Trend
import com.laotoua.dawnislandk.screens.SharedViewModel
import com.laotoua.dawnislandk.screens.adapters.animators.CustomAnimation1
import com.laotoua.dawnislandk.screens.adapters.animators.CustomAnimation2
Expand Down Expand Up @@ -103,8 +102,6 @@ class QuickAdapter<T>(
holder.convertPost(item, sharedViewModel!!.getForumDisplayName(item.fid))
} else if (layoutResId == R.layout.list_item_comment && item is Comment) {
holder.convertComment(item, po)
} else if (layoutResId == R.layout.list_item_trend && item is Trend) {
holder.convertTrend(item)
} else if (layoutResId == R.layout.grid_item_emoji && item is Emoji) {
holder.convertEmoji(item)
} else if (layoutResId == R.layout.grid_item_luwei_sticker && item is String) {
Expand All @@ -129,7 +126,7 @@ class QuickAdapter<T>(

override fun onCreateDefViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
return when (layoutResId) {
R.layout.list_item_post, R.layout.list_item_trend -> {
R.layout.list_item_post -> {
val view = parent.getItemView(layoutResId).applyTextSizeAndLetterSpacing()
PostCardFactory.applySettings(view as MaterialCardView)
createBaseViewHolder(view)
Expand Down Expand Up @@ -197,14 +194,6 @@ class QuickAdapter<T>(
convertExpandSummary(context, payload.visible)
}

private fun BaseViewHolder.convertTrend(item: Trend) {
setText(R.id.trendRank, item.rank)
convertRefId(context, item.id)
setText(R.id.trendForum, item.forum)
setText(R.id.hits, item.hits)
convertContent(context, item.content)
}

private fun BaseViewHolder.convertEmoji(item: Emoji) {
setText(R.id.emoji, item.name)
}
Expand All @@ -230,7 +219,6 @@ class QuickAdapter<T>(
&& oldItem.visible == newItem.visible
}
}
(oldItem is Trend && newItem is Trend) -> oldItem.id == newItem.id
(oldItem is Emoji && newItem is Emoji) -> oldItem == newItem
(oldItem is String && newItem is String) -> oldItem == newItem
else -> throw Exception("Unhandled type comparison")
Expand All @@ -256,9 +244,6 @@ class QuickAdapter<T>(
&& oldItem.title == newItem.title
&& oldItem.name == newItem.name
}
(oldItem is Trend && newItem is Trend) -> {
oldItem.rank == newItem.rank && oldItem.hits == newItem.hits
}
(oldItem is Emoji && newItem is Emoji) -> true
(oldItem is String && newItem is String) -> true
else -> throw Exception("Unhandled type comparison")
Expand Down Expand Up @@ -288,9 +273,6 @@ class QuickAdapter<T>(
newItem.getSimplifiedName()
)
}
(oldItem is Trend && newItem is Trend) -> {
null
}
else -> throw Exception("Unhandled type comparison")
}
}
Expand Down
Loading

0 comments on commit 3e157f6

Please sign in to comment.