diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index c5d14d1..1540851 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/build.gradle b/app/build.gradle index 948e4c5..788664e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,34 +1,34 @@ -apply plugin: 'com.android.application' +apply plugin: "com.android.application" -apply plugin: 'kotlin-android' +apply plugin: "kotlin-android" -apply plugin: 'kotlin-android-extensions' +apply plugin: "kotlin-android-extensions" -apply plugin: 'kotlin-kapt' +apply plugin: "kotlin-kapt" -def cmd = 'git rev-list HEAD --count' +def cmd = "git rev-list HEAD --count" def gitVersion = cmd.execute().text.trim().toInteger() static def getAlphaVersionName() { - 'alpha' + new Date().format('yyyyMMdd') + "alpha" + new Date().format("yyyyMMdd") } android { packagingOptions { - exclude 'lib/*/libRSSupport.so' - exclude 'lib/*/librsjni.so' - exclude 'lib/*/librsjni_androidx.so' + exclude "lib/*/libRSSupport.so" + exclude "lib/*/librsjni.so" + exclude "lib/*/librsjni_androidx.so" } compileSdkVersion 28 - buildToolsVersion '28.0.3' + buildToolsVersion "28.0.3" defaultConfig { - applicationId 'soko.ekibun.bangumi' + applicationId "soko.ekibun.bangumi" minSdkVersion 22 targetSdkVersion 28 versionCode gitVersion versionName getAlphaVersionName() - testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" buildConfigField "boolean", "AUTO_UPDATES", "true" javaCompileOptions { @@ -49,7 +49,7 @@ android { buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } flavorDimensions "versionCode" @@ -66,41 +66,43 @@ android { dependencies { def room_version = "2.2.3" + def glide_version = "4.11.0" + def okhttp_version = "4.6.0" - implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation fileTree(include: ["*.jar"], dir: "libs") implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" implementation "androidx.room:room-rxjava2:$room_version" - implementation 'androidx.appcompat:appcompat:1.1.0' - implementation 'androidx.core:core-ktx:1.1.0' - implementation 'androidx.preference:preference:1.1.0' - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.2.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' - implementation 'com.google.android.material:material:1.2.0-alpha04' - implementation 'com.google.code.gson:gson:2.8.5' - implementation 'org.jsoup:jsoup:1.11.2' - implementation 'com.github.bumptech.glide:glide:4.10.0' - kapt 'com.github.bumptech.glide:compiler:4.10.0' - implementation 'com.zlc.glide:webpdecoder:1.6.4.10.0' - implementation 'com.github.bumptech.glide:okhttp3-integration:4.10.0' - implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.3' - implementation 'com.squareup.okhttp3:okhttp:4.2.2' - implementation 'com.squareup.okhttp3:okhttp-brotli:4.2.1' - implementation 'com.squareup.okhttp3:logging-interceptor:4.2.2' + implementation "androidx.appcompat:appcompat:1.1.0" + implementation "androidx.core:core-ktx:1.1.0" + implementation "androidx.preference:preference:1.1.0" + testImplementation "junit:junit:4.12" + androidTestImplementation "androidx.test:runner:1.2.0" + androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0" + implementation "androidx.constraintlayout:constraintlayout:1.1.3" + implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" + implementation "com.google.android.material:material:1.2.0-alpha04" + implementation "com.google.code.gson:gson:2.8.6" + implementation "org.jsoup:jsoup:1.13.1" + implementation "com.github.bumptech.glide:glide:${glide_version}" + kapt "com.github.bumptech.glide:compiler:${glide_version}" + implementation "com.zlc.glide:webpdecoder:1.7.${glide_version}" + implementation "com.github.bumptech.glide:okhttp3-integration:${glide_version}" + implementation "com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.3" + implementation "com.squareup.okhttp3:okhttp:${okhttp_version}" + implementation "com.squareup.okhttp3:okhttp-brotli:${okhttp_version}" + implementation "com.squareup.okhttp3:logging-interceptor:${okhttp_version}" implementation "io.reactivex.rxjava2:rxjava:2.2.19" implementation "io.reactivex.rxjava2:rxandroid:2.1.1" - implementation 'jp.wasabeef:glide-transformations:4.0.1' - implementation 'com.github.siyamed:android-shape-imageview:0.9.3' - implementation 'com.zhy:base-adapter:3.0.3' - implementation 'com.nshmura:recyclertablayout:1.5.0' - implementation 'com.github.chrisbanes:PhotoView:2.1.4' - implementation 'am.util:viewpager:25.3.0' - implementation 'com.jakewharton:disklrucache:2.0.2' - implementation 'com.caverock:androidsvg:1.2.1' - implementation 'com.umeng.umsdk:analytics:8.0.0' - implementation 'com.umeng.umsdk:common:2.0.0' + implementation "jp.wasabeef:glide-transformations:4.0.1" + implementation "com.github.siyamed:android-shape-imageview:0.9.3" + implementation "com.zhy:base-adapter:3.0.3" + implementation "com.nshmura:recyclertablayout:1.5.0" + implementation "com.github.chrisbanes:PhotoView:2.1.4" + implementation "am.util:viewpager:25.3.0" + implementation "com.jakewharton:disklrucache:2.0.2" + implementation "com.caverock:androidsvg:1.2.1" + implementation "com.umeng.umsdk:analytics:8.0.0" + implementation "com.umeng.umsdk:common:2.0.0" } diff --git a/app/src/main/java/soko/ekibun/bangumi/api/bangumi/bean/Topic.kt b/app/src/main/java/soko/ekibun/bangumi/api/bangumi/bean/Topic.kt index c3cab8d..0476690 100644 --- a/app/src/main/java/soko/ekibun/bangumi/api/bangumi/bean/Topic.kt +++ b/app/src/main/java/soko/ekibun/bangumi/api/bangumi/bean/Topic.kt @@ -88,6 +88,26 @@ data class Topic( } } + private fun parsePost(str: String): List { + val doc = Jsoup.parse(str) + doc.outputSettings().prettyPrint(false) + var relate: TopicPost? = null + return doc.select(".re_info").mapNotNull { + val post = TopicPost.parse(it.parent()) + when { + post == null -> null + post.isSub -> { + relate?.children?.add(post) + null + } + else -> { + relate = post + post + } + } + } + } + /** * 加载帖子(Sax) * @param topic Topic @@ -108,23 +128,7 @@ data class Topic( Observable.just(0).observeOn(Schedulers.computation()).takeWhile { !emitter.isDisposed }.map { - val doc = Jsoup.parse(str.joinToString("")) - doc.outputSettings().prettyPrint(false) - var relate: TopicPost? = null - doc.select(".re_info").mapNotNull { - val post = TopicPost.parse(it.parent()) - when { - post == null -> null - post.isSub -> { - relate?.children?.add(post) - null - } - else -> { - relate = post - post - } - } - } + parsePost(str.joinToString("")) } } @@ -134,6 +138,7 @@ data class Topic( if (!emitter.isDisposed) emitter.onError(it) }) + val firstReplies = ArrayList() val updateReply = { str: String -> if (beforeData.isEmpty()) { beforeData = str @@ -167,6 +172,10 @@ data class Topic( ) } if (!emitter.isDisposed) emitter.onNext(true) + } else if (firstReplies.isEmpty()) { + val posts = parsePost(str) + firstReplies.addAll(posts) + emitter.onNext(posts) } else { replyPub.onNext(str) } @@ -194,8 +203,7 @@ data class Topic( topic.error = error?.text()?.let { Pair(it, Bangumi.parseUrl(error.selectFirst("a")?.attr("href") ?: "")) } - topic.replies = observable.blockingIterable().flatten() - .let { replies -> replies.sortedBy { it.floor } } + topic.replies = firstReplies.plus(observable.blockingIterable().flatten()).sortedBy { it.floor } if (!emitter.isDisposed) { emitter.onNext(false) emitter.onComplete() diff --git a/app/src/main/java/soko/ekibun/bangumi/ui/say/SayAdapter.kt b/app/src/main/java/soko/ekibun/bangumi/ui/say/SayAdapter.kt index a32514a..035d7cd 100644 --- a/app/src/main/java/soko/ekibun/bangumi/ui/say/SayAdapter.kt +++ b/app/src/main/java/soko/ekibun/bangumi/ui/say/SayAdapter.kt @@ -53,11 +53,10 @@ class SayAdapter(data: MutableList? = null) : pinnedIndex = it container.visibility = View.VISIBLE avatar.setOnClickListener { v -> -// onItemChildClickListener?.onItemChildClick(this, v, it) + setOnItemChildClick(v, it) } avatar.setOnLongClickListener { v -> -// onItemChildLongClickListener?.onItemChildLongClick(this, v, it) ?: false - false + setOnItemChildLongClick(v, it) } updateAvatar(avatar, item) } @@ -68,8 +67,12 @@ class SayAdapter(data: MutableList? = null) : private val imageSizes = HashMap() private val largeContent = WeakHashMap() override fun convert(holder: BaseViewHolder, item: SaySection) { -// holder.addOnClickListener(R.id.item_avatar) -// holder.addOnLongClickListener(R.id.item_avatar) + holder.itemView.item_avatar.setOnClickListener { + setOnItemChildClick(it, holder.layoutPosition) + } + holder.itemView.item_avatar.setOnLongClickListener { + setOnItemChildLongClick(it, holder.layoutPosition) + } holder.itemView.item_user.text = item.t.user.name if (holder.adapterPosition == 0) holder.setBackgroundResource(R.id.item_layout, R.drawable.bg_round_dialog) diff --git a/app/src/main/java/soko/ekibun/bangumi/ui/search/SearchHistoryAdapter.kt b/app/src/main/java/soko/ekibun/bangumi/ui/search/SearchHistoryAdapter.kt index 5f3d973..00dfd57 100644 --- a/app/src/main/java/soko/ekibun/bangumi/ui/search/SearchHistoryAdapter.kt +++ b/app/src/main/java/soko/ekibun/bangumi/ui/search/SearchHistoryAdapter.kt @@ -2,6 +2,7 @@ package soko.ekibun.bangumi.ui.search import com.chad.library.adapter.base.BaseQuickAdapter import com.chad.library.adapter.base.viewholder.BaseViewHolder +import kotlinx.android.synthetic.main.item_search_history.view.* import soko.ekibun.bangumi.R /** @@ -13,6 +14,8 @@ class SearchHistoryAdapter(data: MutableList? = null) : override fun convert(holder: BaseViewHolder, item: String) { holder.setText(R.id.item_search_key, item) -// holder.addOnClickListener(R.id.item_remove_key) + holder.itemView.item_remove_key.setOnClickListener { + setOnItemChildClick(it, holder.layoutPosition) + } } } diff --git a/app/src/main/java/soko/ekibun/bangumi/ui/topic/EmojiAdapter.kt b/app/src/main/java/soko/ekibun/bangumi/ui/topic/EmojiAdapter.kt index 5d68471..592a1d9 100644 --- a/app/src/main/java/soko/ekibun/bangumi/ui/topic/EmojiAdapter.kt +++ b/app/src/main/java/soko/ekibun/bangumi/ui/topic/EmojiAdapter.kt @@ -16,7 +16,9 @@ class EmojiAdapter(data: MutableList>? = null) : @SuppressLint("SetTextI18n") override fun convert(holder: BaseViewHolder, item: Pair) { -// holder.addOnClickListener(R.id.item_emoji) + holder.itemView.item_emoji.setOnClickListener { + setOnItemChildClick(it, holder.layoutPosition) + } GlideUtil.with(holder.itemView.item_emoji) ?.load(item.second) ?.into(holder.itemView.item_emoji) diff --git a/app/src/main/java/soko/ekibun/bangumi/ui/topic/ReplyDialog.kt b/app/src/main/java/soko/ekibun/bangumi/ui/topic/ReplyDialog.kt index 29e2719..e3dcc15 100644 --- a/app/src/main/java/soko/ekibun/bangumi/ui/topic/ReplyDialog.kt +++ b/app/src/main/java/soko/ekibun/bangumi/ui/topic/ReplyDialog.kt @@ -45,8 +45,6 @@ import java.lang.ref.WeakReference * @property postTitle String? * @property bbCode Boolean * @property title String - * @property onClickImage Function1 - * @property onClickUrl Function1 */ class ReplyDialog : BaseDialog(R.layout.dialog_reply) { @@ -153,7 +151,6 @@ class ReplyDialog : BaseDialog(R.layout.dialog_reply) { override fun onViewCreated(view: View) { bbCode = PreferenceManager.getDefaultSharedPreferences(view.context).getBoolean("use_bbcode", false) collapseImageGetter = CollapseUrlDrawable.CollapseImageGetter(view.item_input) - val weakRef: WeakReference = WeakReference(view.item_input) view.item_title_container.visibility = if (postTitle == null) View.GONE else View.VISIBLE view.item_title.setText(postTitle) @@ -197,12 +194,12 @@ class ReplyDialog : BaseDialog(R.layout.dialog_reply) { } else { val drawable = collapseImageGetter.createDrawable() drawable.url = emojiList[position].second - drawable.container = weakRef - drawable.loadImage() view.item_input.editableText.insert( view.item_input.selectionStart, HtmlUtil.createImageSpan(ImageSpan(drawable, emojiList[position].first, ImageSpan.ALIGN_BASELINE)) ) + drawable.container = WeakReference(view.item_input) + drawable.loadImage() } } view.item_btn_format.setOnClickListener { v -> @@ -286,14 +283,6 @@ class ReplyDialog : BaseDialog(R.layout.dialog_reply) { } } - val onClickImage = { view: View, _: ImageSpan -> - //Toast.makeText(context?:return@click, (it.drawable as? UrlDrawable)?.url?:"", Toast.LENGTH_LONG).show() - } - - val onClickUrl = { _: String -> - //Toast.makeText(context?:return@click, url, Toast.LENGTH_LONG).show() - } - override fun onDismiss(dialog: DialogInterface) { super.onDismiss(dialog) callback( diff --git a/app/src/main/java/soko/ekibun/bangumi/util/span/CollapseUrlDrawable.kt b/app/src/main/java/soko/ekibun/bangumi/util/span/CollapseUrlDrawable.kt index cf4c0a2..db57bf0 100644 --- a/app/src/main/java/soko/ekibun/bangumi/util/span/CollapseUrlDrawable.kt +++ b/app/src/main/java/soko/ekibun/bangumi/util/span/CollapseUrlDrawable.kt @@ -4,6 +4,7 @@ import android.graphics.* import android.graphics.drawable.Animatable import android.graphics.drawable.Drawable import android.text.style.ImageSpan +import android.util.Log import android.util.Size import android.view.View import android.widget.TextView @@ -25,6 +26,7 @@ open class CollapseUrlDrawable( val width = wrapWidth(if (error == false) drawable.intrinsicWidth.toFloat() else -1f) Size(width.toInt(), (drawable.intrinsicHeight * width / drawable.intrinsicWidth).toInt()) }() + Log.v("update", "$drawable size: $size") (this.drawable as? Animatable)?.stop() this.drawable?.callback = null this.drawable = drawable @@ -47,6 +49,15 @@ open class CollapseUrlDrawable( span.image = ImageSpan(this, url ?: "", ImageSpan.ALIGN_BASELINE) it.editableText.setSpan(span.image, start, end, flags) } + it.editableText.getSpans(0, it.editableText.length, ImageSpan::class.java).filter { span -> + span.drawable == this + }.forEach { span -> + val start = it.editableText.getSpanStart(span) + val end = it.editableText.getSpanEnd(span) + val flags = it.editableText.getSpanFlags(span) + it.editableText.removeSpan(span) + it.editableText.setSpan(span, start, end, flags) + } it.invalidate() } } diff --git a/app/src/main/java/soko/ekibun/bangumi/util/span/UrlDrawable.kt b/app/src/main/java/soko/ekibun/bangumi/util/span/UrlDrawable.kt index 6707fed..06fcd03 100644 --- a/app/src/main/java/soko/ekibun/bangumi/util/span/UrlDrawable.kt +++ b/app/src/main/java/soko/ekibun/bangumi/util/span/UrlDrawable.kt @@ -5,6 +5,8 @@ import android.graphics.drawable.Animatable import android.graphics.drawable.AnimationDrawable import android.graphics.drawable.Drawable import android.net.Uri +import android.text.Spannable +import android.text.style.ImageSpan import android.util.Size import android.widget.TextView import androidx.swiperefreshlayout.widget.CircularProgressDrawable @@ -65,8 +67,19 @@ open class UrlDrawable( this.drawable?.bounds = bounds updateBuffer() - container?.get()?.text = container?.get()?.text - container?.get()?.invalidate() + container?.get()?.let { + val text = (it.text as? Spannable) ?: return@let + text.getSpans(0, text.length, ImageSpan::class.java)?.filter { span -> + span.drawable == this + }?.forEach { span -> + val start = text.getSpanStart(span) + val end = text.getSpanEnd(span) + val flags = text.getSpanFlags(span) + text.removeSpan(span) + text.setSpan(span, start, end, flags) + } + it.invalidate() + } } /**