Skip to content

Commit

Permalink
Added some UI to display situation reports.
Browse files Browse the repository at this point in the history
  • Loading branch information
codeka committed May 12, 2020
1 parent 522587f commit 0ec7ff1
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 29 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.android.tools.build:gradle:4.0.0-beta05'
classpath 'com.google.gms:google-services:4.3.3'
classpath 'com.squareup.wire:wire-gradle-plugin:3.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
Expand Down
11 changes: 8 additions & 3 deletions client/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ android {
vectorDrawables.useSupportLibrary = true
}
compileOptions {
coreLibraryDesugaringEnabled true

sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Expand Down Expand Up @@ -102,15 +104,18 @@ def getVersionCodeFromGit() {
}

dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.5'

implementation 'androidx.appcompat:appcompat:1.1.0'
implementation "androidx.core:core-ktx:1.2.0"
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta5'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.transition:transition:1.3.1'
implementation 'com.google.android.material:material:1.2.0-alpha06'
implementation 'com.google.android.gms:play-services-base:17.2.1'
implementation 'com.google.android.gms:play-services-auth:18.0.0'
implementation 'com.google.firebase:firebase-core:17.4.0'
implementation 'com.google.firebase:firebase-messaging:20.1.6'
implementation 'com.google.firebase:firebase-core:17.4.1'
implementation 'com.google.firebase:firebase-messaging:20.1.7'
implementation 'com.google.guava:guava:24.1-android'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.squareup.wire:wire-runtime:3.1.0'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package au.com.codeka.warworlds.client.game.sitrep

import android.text.Html
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import au.com.codeka.warworlds.client.R
import au.com.codeka.warworlds.client.concurrency.Threads
import au.com.codeka.warworlds.client.game.build.BuildViewHelper
import au.com.codeka.warworlds.client.game.world.ImageHelper
import au.com.codeka.warworlds.client.game.world.StarManager
import au.com.codeka.warworlds.common.proto.Design
import au.com.codeka.warworlds.common.proto.SituationReport
import au.com.codeka.warworlds.common.proto.Star
import au.com.codeka.warworlds.common.sim.DesignHelper
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.util.*


class SitReportAdapter(private val layoutInflater: LayoutInflater)
: RecyclerView.Adapter<SitReportAdapter.SitReportViewHolder>() {
private val rows = ArrayList<RowData>()
private val starRowMap = HashMap<Long, Set<Int>>()

companion object {
val dateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("dd MMM, yyyy", Locale.ENGLISH)
val timeFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("h:mm\na", Locale.ENGLISH)
}

fun refresh(sitReports: List<SituationReport>) {
Threads.checkOnThread(Threads.UI)

rows.clear()
starRowMap.clear()
var lastDate: LocalDate? = null
for ((i, sitReport) in sitReports.withIndex()) {
val date =
LocalDateTime.ofEpochSecond(sitReport.report_time / 1000, 0, ZoneOffset.UTC).toLocalDate()
if (lastDate == null || lastDate != date) {
rows.add(RowData(date, null))
lastDate = date
}

rows.add(RowData(null, sitReport))

val positions = starRowMap[sitReport.star_id] ?: HashSet()
starRowMap[sitReport.star_id] = positions
positions.plus(i)
}

notifyDataSetChanged()
}

fun onStarUpdated(star: Star) {
val positions = starRowMap[star.id]
if (positions != null) {
for (position in positions) {
notifyItemChanged(position)
}
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SitReportViewHolder {
val view = layoutInflater.inflate(viewType, parent, false)
return SitReportViewHolder(viewType, view)
}

override fun getItemCount(): Int {
return rows.size
}

override fun getItemViewType(position: Int): Int {
return when {
rows[position].date != null -> R.layout.sitreport_row_day
else -> R.layout.sitreport_row
}
}

override fun onBindViewHolder(holder: SitReportViewHolder, position: Int) {
holder.bind(rows[position])
}

class SitReportViewHolder(viewType: Int, itemView: View) : RecyclerView.ViewHolder(itemView) {
private val dateViewBinding: DateViewBinding?
private val sitReportViewBinding: SitReportViewBinding?

init {
if (viewType == R.layout.sitreport_row_day) {
dateViewBinding = DateViewBinding(itemView)
sitReportViewBinding = null
} else {
dateViewBinding = null
sitReportViewBinding = SitReportViewBinding(itemView)
}
}

fun bind(row: RowData) {
when {
row.date != null -> dateViewBinding!!.bind(row.date)
row.sitReport != null -> sitReportViewBinding!!.bind(row.sitReport)
}
}
}

class DateViewBinding(view: View) {
private val dateView: TextView = view as TextView

fun bind(date: LocalDate) {
// TODO: special-case TODAY and YESTERDAY
dateView.text = date.format(dateFormat)
}
}

class SitReportViewBinding(view: View) {
private val timeView: TextView = view.findViewById(R.id.time)
private val starIconView: ImageView = view.findViewById(R.id.star_icon)
private val designIconView: ImageView = view.findViewById(R.id.design_icon)
private val reportTitleView: TextView = view.findViewById(R.id.report_title)
private val reportDetailsView: TextView = view.findViewById(R.id.report_details)

fun bind(sitReport: SituationReport) {
val res = timeView.context.resources

val reportTime =
LocalDateTime.ofEpochSecond(sitReport.report_time / 1000, 0, ZoneOffset.UTC).toLocalTime()
timeView.text = reportTime.format(timeFormat)

val star = StarManager.getStar(sitReport.star_id)
if (star != null) {
ImageHelper.bindStarIcon(starIconView, star)
}

val design: Design?
when {
sitReport.build_complete_record != null -> {
design = DesignHelper.getDesign(sitReport.build_complete_record.design_type)
reportTitleView.text =
Html.fromHtml(res.getString(R.string.build_complete, star?.name ?: "..."))

if (design.design_kind == Design.DesignKind.SHIP) {
// TODO: handle was_destroyed when we have it.
reportDetailsView.text =
res.getString(
R.string.fleet_details_not_destroyed,
sitReport.build_complete_record.count.toFloat(),
design.display_name)
} else {
reportDetailsView.text = res.getString(R.string.build_details, design.display_name)
}
}
sitReport.move_complete_record != null -> {
design = DesignHelper.getDesign(sitReport.move_complete_record.design_type)
reportTitleView.text =
Html.fromHtml(res.getString(R.string.fleet_move_complete, star?.name ?: "..."))

val resId = if (design.design_kind == Design.DesignKind.SHIP
&& sitReport.move_complete_record.was_destroyed == true) {
R.string.fleet_details_destroyed
} else /* if (design.design_kind == Design.DesignKind.SHIP) */ {
R.string.fleet_details_not_destroyed
}
reportDetailsView.text =
res.getString(resId, sitReport.move_complete_record.num_ships, design.display_name)
}
else -> {
design = null
reportTitleView.text =
Html.fromHtml(res.getString(R.string.attack_on_star, star?.name ?: "..."))
}
}
if (design != null) {
BuildViewHelper.setDesignIcon(design, designIconView)
}
}
}

data class RowData(val date: LocalDate?, val sitReport: SituationReport?)
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
package au.com.codeka.warworlds.client.game.sitrep

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.widget.ListView
import android.widget.RelativeLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import au.com.codeka.warworlds.client.R
import au.com.codeka.warworlds.common.proto.SituationReport
import au.com.codeka.warworlds.common.proto.Star

class SitReportLayout(context: Context, callback: Callback) : RelativeLayout(context) {
interface Callback {
fun onStarClick(star: Star?)
}

private val adapter: SitReportAdapter

init {
View.inflate(context, R.layout.sitreport, this)
setBackgroundColor(context.resources.getColor(R.color.default_background))
val lv = findViewById<ListView>(R.id.search_result)
val rv = findViewById<RecyclerView>(R.id.sit_reports)
adapter = SitReportAdapter(LayoutInflater.from(context))
rv.adapter = adapter
rv.layoutManager = LinearLayoutManager(context)
}

fun refresh(sitReports: List<SituationReport>) {
adapter.refresh(sitReports)
}

/*
adapter = StarSearchListAdapter(LayoutInflater.from(context))
lv.adapter = adapter
adapter.setCursor(StarManager.myStars)
lv.onItemClickListener = AdapterView.OnItemClickListener {
_: AdapterView<*>?, _: View?, position: Int, _: Long ->
val star = adapter.getStar(position)
callback.onStarClick(star)
}
*/
fun onStarUpdated(star: Star) {
adapter.onStarUpdated(star)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import au.com.codeka.warworlds.client.game.solarsystem.SolarSystemScreen
import au.com.codeka.warworlds.client.ui.Screen
import au.com.codeka.warworlds.client.ui.ScreenContext
import au.com.codeka.warworlds.client.ui.ShowInfo
import au.com.codeka.warworlds.client.util.eventbus.EventHandler
import au.com.codeka.warworlds.common.Log
import au.com.codeka.warworlds.common.proto.RpcPacket
import au.com.codeka.warworlds.common.proto.SituationReport
Expand All @@ -28,11 +29,19 @@ class SitReportScreen : Screen() {
context.pushScreen(SolarSystemScreen(star!!, -1))
}
})

App.eventBus.register(eventHandler)
}

override fun onDestroy() {
super.onDestroy()

App.eventBus.unregister(eventHandler)
}

fun refresh(sitReports: List<SituationReport>) {
log.info("populating response: ${sitReports.size} reports")
// TODO: implement me!
layout.refresh(sitReports)
}

override fun onShow(): ShowInfo? {
Expand All @@ -49,4 +58,11 @@ class SitReportScreen : Screen() {

return ShowInfo.builder().view(layout).build()
}

private val eventHandler: Any = object : Any() {
@EventHandler
fun onStarUpdated(s: Star) {
layout.onStarUpdated(s)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,16 @@ object ImageHelper {
.into(view)
}

/**
* Bind an image with the given star to the given [ImageView].
*/
fun bindStarIcon(view: ImageView, star: Star) {
val resolver = DimensionResolver(view.context)
val width = resolver.px2dp(view.layoutParams.width.toFloat()).toInt()
val height = resolver.px2dp(view.layoutParams.height.toFloat()).toInt()
bindImage(view, getStarImageUrl(view.context, star, width, height))
}

/** Bind the given star icon to the given span in a [SpannableStringBuilder]. */
fun bindStarIcon(
ssb: SpannableStringBuilder, startIndex: Int, endIndex: Int, context: Context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,16 +294,17 @@ class Server {
private val packetDecodeHandler: PacketDecoder.PacketHandler =
object : PacketDecoder.PacketHandler {
override fun onPacket(decoder: PacketDecoder, pkt: Packet, encodedSize: Int) {
if (pkt.rpc != null) {
handleRpcResponse(pkt.rpc)
return
}

val packetDebug = PacketDebug.getPacketDebug(pkt, encodedSize)
App.eventBus.publish(ServerPacketEvent(
pkt, encodedSize, ServerPacketEvent.Direction.Received, packetDebug))
log.debug("<< %s", packetDebug)
packetDispatcher.dispatch(pkt)

if (pkt.rpc != null) {
// We do some special-casing for RPCs
handleRpcResponse(pkt.rpc)
} else {
packetDispatcher.dispatch(pkt)
}
}

override fun onDisconnect() {
Expand Down
4 changes: 2 additions & 2 deletions client/src/main/res/layout/sitreport.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
android:layout_alignParentEnd="true"
android:src="@android:drawable/ic_menu_search" />

<ListView
android:id="@+id/search_result"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/sit_reports"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/search_button" />
Expand Down
Loading

0 comments on commit 0ec7ff1

Please sign in to comment.