Skip to content

Commit

Permalink
fix comment bug.
Browse files Browse the repository at this point in the history
  • Loading branch information
yueeng committed Jul 13, 2015
1 parent fabff59 commit d035a9a
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 44 deletions.
8 changes: 8 additions & 0 deletions app/src/main/res/layout/comment_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@
android:textSize="@dimen/text_size_summary" />
</LinearLayout>

<TextView
android:id="@+id/text4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:textColor="@color/text_color_summary"
android:textSize="@dimen/text_size_summary" />

<TextView
android:id="@+id/text2"
android:layout_width="match_parent"
Expand Down
67 changes: 35 additions & 32 deletions app/src/main/scala/io/github/yueeng/hacg/Article.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,19 @@ case class Tag(name: String, url: String) extends Parcelable {
}
}

case class Comment(id: Int, content: String, user: String, face: String, time: Option[Date], children: List[Comment]) extends Parcelable {
object Tag {

val CREATOR: Parcelable.Creator[Tag] = new Parcelable.Creator[Tag] {
override def createFromParcel(source: Parcel): Tag = new Tag(
source.readString(),
source.readString()
)

override def newArray(size: Int): Array[Tag] = new Array[Tag](size)
}
}

case class Comment(id: Int, content: String, user: String, face: String, moderation: String, time: Option[Date], children: List[Comment]) extends Parcelable {
def this(e: Element) = {
this(
Comment.ID.findPrefixMatchOf(e.select(">article").attr("id")) match {
Expand All @@ -33,6 +45,7 @@ case class Comment(id: Int, content: String, user: String, face: String, time: O
e.select(">article .comment-content").text(),
e.select(">article .fn").text(),
e.select(">article .avatar").attr("abs:src"),
e.select(">article footer>.comment-awaiting-moderation").text(),
e.select(">article time").attr("datetime"),
e.select(">.children>li").map(e => new Comment(e)).toList
)
Expand All @@ -45,11 +58,32 @@ case class Comment(id: Int, content: String, user: String, face: String, time: O
dest.writeString(content)
dest.writeString(user)
dest.writeString(face)
dest.writeString(moderation)
dest.writeLong(if (time.nonEmpty) time.get.getTime else 0)
dest.writeParcelableArray(children.toArray, flags)
}
}

object Comment {
val ID = """comment-(\d+)""".r
val CREATOR: Parcelable.Creator[Comment] = new Parcelable.Creator[Comment] {
override def createFromParcel(source: Parcel): Comment = new Comment(
source.readInt(),
source.readString(),
source.readString(),
source.readString(),
source.readString(),
source.readLong() match {
case 0 => None
case l => Option(new Date(l))
},
source.readParcelableArray(classOf[Comment].getClassLoader).map(_.asInstanceOf[Comment]).toList
)

override def newArray(size: Int): Array[Comment] = new Array[Comment](size)
}
}

case class Article(title: String,
link: String,
image: String,
Expand Down Expand Up @@ -100,37 +134,6 @@ case class Article(title: String,
}
}

object Tag {

val CREATOR: Parcelable.Creator[Tag] = new Parcelable.Creator[Tag] {
override def createFromParcel(source: Parcel): Tag = new Tag(
source.readString(),
source.readString()
)

override def newArray(size: Int): Array[Tag] = new Array[Tag](size)
}
}

object Comment {
val ID = """comment-(\d+)""".r
val CREATOR: Parcelable.Creator[Comment] = new Parcelable.Creator[Comment] {
override def createFromParcel(source: Parcel): Comment = new Comment(
source.readInt(),
source.readString(),
source.readString(),
source.readString(),
source.readLong() match {
case 0 => None
case l => Option(new Date(l))
},
source.readParcelableArray(classOf[Comment].getClassLoader).map(_.asInstanceOf[Comment]).toList
)

override def newArray(size: Int): Array[Comment] = new Array[Comment](size)
}
}

object Article {

val CREATOR: Parcelable.Creator[Article] = new Parcelable.Creator[Article] {
Expand Down
158 changes: 153 additions & 5 deletions app/src/main/scala/io/github/yueeng/hacg/Common.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package io.github.yueeng.hacg

import java.net._
import java.security.MessageDigest
import java.text.{ParseException, SimpleDateFormat}
import java.util
import java.util.Date
import java.util.concurrent.TimeUnit

import android.content.DialogInterface.OnDismissListener
import android.content.{Context, DialogInterface, Intent}
import android.content.{Context, DialogInterface, Intent, SharedPreferences}
import android.net.Uri
import android.os.{AsyncTask, Bundle}
import android.preference.PreferenceManager
Expand All @@ -18,11 +20,12 @@ import org.jsoup.Jsoup
import org.jsoup.nodes.Document

import scala.collection.JavaConversions._
import scala.language.{implicitConversions, reflectiveCalls}
import scala.collection.mutable
import scala.language.{implicitConversions, postfixOps, reflectiveCalls}
import scala.util.Random

object HAcg {
val config = PreferenceManager.getDefaultSharedPreferences(HAcgApplication.context)
val config = PreferenceManager.getDefaultSharedPreferences(HAcgApplication.instance)

def HOST = config.getString("system.host", "hacg.me")

Expand All @@ -44,11 +47,18 @@ object HAcg {
}

object HAcgApplication {
implicit var context: Context = _
private var _instance: HAcgApplication = _

def instance = _instance
}

class HAcgApplication extends MultiDexApplication {
HAcgApplication.context = this
HAcgApplication._instance = this

override def onCreate(): Unit = {
super.onCreate()
CookieHandler.setDefault(CookieManagerProxy.instance)
}
}

object Common {
Expand Down Expand Up @@ -226,3 +236,141 @@ abstract class ScalaTask[A, P, R] extends AsyncTask[A, P, R] {

def background(params: A*): R
}

class CookieManagerProxy(store: CookieStore, policy: CookiePolicy) extends CookieManager(store, policy) {

private val SetCookie: String = "Set-Cookie"

override def put(uri: URI, headers: util.Map[String, util.List[String]]): Unit = {
super.put(uri, headers)
getCookieStore.get(uri)
.filter(o => o.getDomain != null && !o.getDomain.startsWith("."))
.foreach(o => o.setDomain(s".${o.getDomain}"))
}

def put(uri: URI, cookies: String): Unit = cookies match {
case null =>
case _ =>
this.put(uri, Map[String, util.List[String]](SetCookie -> cookies.split(";").map(_.trim).toList))
}
}

object CookieManagerProxy {
val instance = new CookieManagerProxy(new PersistCookieStore(HAcgApplication.instance), CookiePolicy.ACCEPT_ALL)
}

/**
* PersistentCookieStore
* Created by Rain on 2015/7/1.
*/
class PersistCookieStore(context: Context) extends CookieStore {
private final val map = new mutable.HashMap[URI, mutable.HashSet[HttpCookie]]
private final val pref: SharedPreferences = context.getSharedPreferences("cookies.pref", Context.MODE_PRIVATE)

pref.getAll.collect { case (k: String, v: String) if !v.isEmpty => (k, v.split(",")) }
.foreach { o =>
map(URI.create(o._1)) = mutable.HashSet() ++= o._2.flatMap {
c => try HttpCookie.parse(c) catch {
case _: Throwable => Nil
}
}
}

implicit class httpCookie(c: HttpCookie) {
def string: String = {
if (c.getVersion != 0) {
return c.toString
}
Map(c.getName -> c.getValue, "domain" -> c.getDomain)
.view
.filter(_._2 != null)
.filter(!_._2.isEmpty)
.map(o => s"${o._1}=${o._2}")
.mkString("; ")
}
}

private def cookiesUri(uri: URI): URI = {
if (uri == null) {
return null
}
try new URI("http", uri.getHost, null, null) catch {
case e: URISyntaxException => uri
}
}

override def add(url: URI, cookie: HttpCookie): Unit = map.synchronized {
if (cookie == null) {
throw new NullPointerException("cookie == null")
}
cookie.getDomain match {
case domain if !domain.startsWith(".") => cookie.setDomain(s".$domain")
case _ =>
}

val uri = cookiesUri(url)

if (map.contains(uri)) {
map(uri) += cookie
} else {
map(uri) = new mutable.HashSet() += cookie
}

pref.edit.putString(uri.toString, map(uri).map(_.string).toSet.mkString(",")).apply()
}

def remove(url: URI, cookie: HttpCookie): Boolean = map.synchronized {
if (cookie == null) {
throw new NullPointerException("cookie == null")
}
val uri = cookiesUri(url)
map.get(uri) match {
case Some(cookies) if cookies.contains(cookie) =>
cookies.remove(cookie)
pref.edit.putString(uri.toString, cookies.map(_.string).toSet.mkString(",")).apply()
true
case _ => false
}
}

override def removeAll(): Boolean = map.synchronized {
val result = map.nonEmpty
map.clear()
pref.edit.clear.apply()
result
}

override def getURIs: util.List[URI] = map.synchronized {
map.keySet.filter(o => o != null).toList
}

def expire(uri: URI, cookies: mutable.HashSet[HttpCookie], edit: SharedPreferences.Editor)(fn: HttpCookie => Boolean = c => true) = {
cookies.filter(fn).filter(_.hasExpired) match {
case ex if ex.nonEmpty =>
cookies --= ex
edit.putString(uri.toString, cookies.map(_.string).toSet.mkString(",")).apply()
case _ =>
}
}

override def getCookies: util.List[HttpCookie] = map.synchronized {
(pref.edit() /: map) { (e, o) => expire(o._1, o._2, e)(); e }.apply()
map.values.flatten.toList.distinct
}

override def get(uri: URI): util.List[HttpCookie] = map.synchronized {
if (uri == null) {
throw new NullPointerException("uri == null")
}
val edit = pref.edit()
map.get(uri) match {
case Some(cookies) => expire(uri, cookies, edit)()
case _ =>
}
map.filter(_._1 != uri).foreach {
o => expire(o._1, o._2, edit)(c => HttpCookie.domainMatches(c.getDomain, uri.getHost))
}
edit.apply()
(map.getOrElse(uri, Nil) ++ map.values.flatMap(o => o.filter(c => HttpCookie.domainMatches(c.getDomain, uri.getHost)))).toList.distinct
}
}
5 changes: 0 additions & 5 deletions app/src/main/scala/io/github/yueeng/hacg/Controls.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.github.yueeng.hacg

import android.content.Context
import android.support.v4.app.{FragmentManager, FragmentStatePagerAdapter}
import android.support.v7.widget.{LinearLayoutManager, RecyclerView}
import android.view.{View, ViewGroup}
import io.github.yueeng.hacg.Common.viewClick
Expand Down Expand Up @@ -115,8 +114,4 @@ object ViewEx {
override def refresh(): Unit = view.setVisibility(if (value) View.VISIBLE else View.INVISIBLE)
}

}

abstract class HacgFragmentStatePagerAdapter(fm: FragmentManager) extends FragmentStatePagerAdapter(fm){

}
12 changes: 10 additions & 2 deletions app/src/main/scala/io/github/yueeng/hacg/InfoActivity.scala
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,10 @@ class InfoFragment extends Fragment {
_progress2.value = false
if (result._1) {
_post(COMMENT) = ""
_url = null
_adapter.data.clear()
_adapter.notifyDataSetChanged()
query(_article.link, QUERY_COMMENT)
}
Toast.makeText(getActivity, result._2, Toast.LENGTH_LONG).show()
}
Expand Down Expand Up @@ -353,7 +357,7 @@ class InfoFragment extends Fragment {
.removeAttr("height")
})
(
if (content) using(scala.io.Source.fromInputStream(HAcgApplication.context.getAssets.open("template.html"))) {
if (content) using(scala.io.Source.fromInputStream(HAcgApplication.instance.getAssets.open("template.html"))) {
reader => reader.mkString.replace("{{title}}",
_article.title).replace("{{body}}", entry.html()
.replaceAll( """(?<!/|:)\b[a-zA-Z0-9]{40}\b""", """magnet:?xt=urn:btih:$0""")
Expand All @@ -378,6 +382,7 @@ class InfoFragment extends Fragment {
_web.value = (data._1, url)
}
if (comment) {
data._2.filter(_.moderation.isNonEmpty).foreach(println)
_adapter.data ++= data._2
_adapter.notifyDataSetChanged()

Expand Down Expand Up @@ -405,6 +410,7 @@ class InfoFragment extends Fragment {
val text1: TextView = view.findViewById(R.id.text1)
val text2: TextView = view.findViewById(R.id.text2)
val text3: TextView = view.findViewById(R.id.text3)
val text4: TextView = view.findViewById(R.id.text4)
val image: ImageView = view.findViewById(R.id.image1)
val list: RecyclerView = view.findViewById(R.id.list1)
val adapter = new CommentAdapter
Expand All @@ -425,7 +431,9 @@ class InfoFragment extends Fragment {
holder.text1.setText(item.user)
holder.text2.setText(item.content)
holder.text3.setText(item.time.map(datafmt.format).orNull)
holder.text3.setVisibility(if (item.time.nonEmpty) View.VISIBLE else View.GONE)
holder.text3.setVisibility(if (item.time.isEmpty) View.GONE else View.VISIBLE)
holder.text4.setText(item.moderation)
holder.text4.setVisibility(if (item.moderation.isNullOrEmpty) View.GONE else View.VISIBLE)
holder.adapter.data.clear()
holder.adapter.data ++= item.children
holder.adapter.notifyDataSetChanged()
Expand Down

0 comments on commit d035a9a

Please sign in to comment.