Commit 23193a4a authored by Daniel Wolf's avatar Daniel Wolf
Browse files

Added a detailed view for queries (shown by clicking one)

parent b629a132
......@@ -34,12 +34,6 @@ class MainActivity : NavigationDrawerActivity() {
val view = layoutInflater.inflate(R.layout.menu_cardview, viewParent, false)
view
}
GlobalScope.launch {
val all = getDatabase().dnsQueryRepository().getAllAsync(GlobalScope)
for (dnsQuery in all) {
println(dnsQuery)
}
}
}
override fun createDrawerItems(): MutableList<DrawerItem> {
......
......@@ -4,15 +4,13 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.frostnerd.cacheadapter.ModelAdapterBuilder
import androidx.fragment.app.FragmentPagerAdapter
import com.frostnerd.smokescreen.R
import com.frostnerd.smokescreen.database.getDatabase
import com.frostnerd.smokescreen.util.LiveDataSource
import kotlinx.android.synthetic.main.fragment_querylog.*
import com.frostnerd.smokescreen.database.entities.DnsQuery
import com.frostnerd.smokescreen.fragment.querylogfragment.QueryLogDetailFragment
import com.frostnerd.smokescreen.fragment.querylogfragment.QueryLogListFragment
import kotlinx.android.synthetic.main.fragment_querylog_main.*
/**
* Copyright Daniel Wolf 2018
......@@ -24,35 +22,53 @@ import kotlinx.android.synthetic.main.fragment_querylog.*
* development@frostnerd.com
*/
class QueryLogFragment : Fragment() {
lateinit var listFragment: QueryLogListFragment
lateinit var detailFragment: QueryLogDetailFragment
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return layoutInflater.inflate(R.layout.fragment_querylog, container, false)
return inflater.inflate(R.layout.fragment_querylog_main, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val live = requireContext().getDatabase().dnsQueryDao().getAllLive()
val source = LiveDataSource(this, live, true) {
list.smoothScrollToPosition(0)
listFragment = QueryLogListFragment()
detailFragment = QueryLogDetailFragment()
viewpager.adapter = createViewAdapter()
tabLayout.setupWithViewPager(viewpager)
}
fun displayQueryDetailed(query:DnsQuery, switchToDetailView:Boolean = true) {
val hadQuery = detailFragment.isShowingQuery()
detailFragment.showQuery(query)
if(!hadQuery) viewpager.adapter?.notifyDataSetChanged()
else {
val tab = tabLayout.getTabAt(1)
tab?.text = query.shortName
}
val adapter = ModelAdapterBuilder.newBuilder(source) {
viewBuilder = { parent, viewType ->
layoutInflater.inflate(R.layout.item_logged_query, parent, false)
}
getItemCount = {
source.currentSize()
}
bindModelView = { viewHolder, position, data ->
viewHolder.itemView.findViewById<TextView>(R.id.text).text = data.shortName + " " + data.type + "(" + data.name + ")"
if(switchToDetailView) viewpager.currentItem = 1
}
private fun createViewAdapter(): FragmentPagerAdapter {
return object : FragmentPagerAdapter(childFragmentManager) {
override fun getItem(position: Int): Fragment {
return when (position) {
0 -> listFragment
else -> detailFragment
}
}
bindNonModelView = { viewHolder, position ->
override fun getCount(): Int {
return if (detailFragment.isShowingQuery()) 2 else 1
}
runOnUiThread = {
requireActivity().runOnUiThread(it)
override fun getPageTitle(position: Int): CharSequence? {
return when (position) {
0 -> getString(R.string.menu_querylogging)
else -> detailFragment.currentQuery?.shortName
}
}
}.build()
list.layoutManager = LinearLayoutManager(requireContext())
list.adapter = adapter
}
}
}
\ No newline at end of file
package com.frostnerd.smokescreen.fragment.querylogfragment
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.frostnerd.smokescreen.R
import com.frostnerd.smokescreen.database.entities.DnsQuery
import kotlinx.android.synthetic.main.fragment_querylog_detail.*
import java.text.DateFormat
import java.util.*
/**
* Copyright Daniel Wolf 2018
* All rights reserved.
* Code may NOT be used without proper permission, neither in binary nor in source form.
* All redistributions of this software in source code must retain this copyright header
* All redistributions of this software in binary form must visibly inform users about usage of this software
* <p>
* development@frostnerd.com
*/
class QueryLogDetailFragment : Fragment() {
var currentQuery: DnsQuery? = null
private set
private lateinit var timeFormatSameDay:DateFormat
private lateinit var timeFormatDifferentDay:DateFormat
private var viewCreated = false
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_querylog_detail, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewCreated = true
setupTimeFormat()
updateUi()
}
private fun setupTimeFormat() {
val locale = getLocale()
timeFormatSameDay = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale)
timeFormatDifferentDay = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale)
}
private fun getLocale(): Locale {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
resources.configuration.locales.get(0)!!
} else{
@Suppress("DEPRECATION")
resources.configuration.locale!!
}
}
fun isShowingQuery(): Boolean {
return currentQuery != null
}
fun showQuery(query: DnsQuery) {
val wasUpdated = query != currentQuery
currentQuery = query
if (wasUpdated) {
updateUi()
}
}
private fun updateUi() {
val query = currentQuery
if(query != null && viewCreated) {
if(isTimeStampToday(query.questionTime)) {
queryTime.text = timeFormatSameDay.format(query.questionTime)
} else {
queryTime.text = timeFormatDifferentDay.format(query.questionTime)
}
if(query.responseTime >= query.questionTime) {
latency.text = (query.responseTime - query.questionTime).toString() + " ms"
} else {
latency.text = "-"
}
longName.text = query.name
type.text = query.type.name
askedServer.text = query.askedServer ?: "-"
}
}
private fun isTimeStampToday(timestamp:Long):Boolean {
return timestamp >= getStartOfDay()
}
private fun getStartOfDay():Long {
val calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
calendar.set(Calendar.MILLISECOND, 0)
return calendar.timeInMillis
}
}
\ No newline at end of file
package com.frostnerd.smokescreen.fragment.querylogfragment
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import com.frostnerd.cacheadapter.ModelAdapterBuilder
import com.frostnerd.smokescreen.R
import com.frostnerd.smokescreen.database.entities.DnsQuery
import com.frostnerd.smokescreen.database.getDatabase
import com.frostnerd.smokescreen.fragment.QueryLogFragment
import com.frostnerd.smokescreen.util.LiveDataSource
import kotlinx.android.synthetic.main.fragment_querylog_list.*
/**
* Copyright Daniel Wolf 2018
* All rights reserved.
* Code may NOT be used without proper permission, neither in binary nor in source form.
* All redistributions of this software in source code must retain this copyright header
* All redistributions of this software in binary form must visibly inform users about usage of this software
* <p>
* development@frostnerd.com
*/
class QueryLogListFragment: Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return layoutInflater.inflate(R.layout.fragment_querylog_list, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val live = requireContext().getDatabase().dnsQueryDao().getAllLive()
val source = LiveDataSource(this, live, true) {
list.smoothScrollToPosition(0)
}
val adapter = ModelAdapterBuilder.newBuilder(source) {
viewBuilder = { parent, viewType ->
val createdView = layoutInflater.inflate(R.layout.item_logged_query, parent, false)
createdView.setOnClickListener {
displayQuery(it.tag as DnsQuery)
}
createdView
}
getItemCount = {
source.currentSize()
}
bindModelView = { viewHolder, position, data ->
viewHolder.itemView.findViewById<TextView>(R.id.text).text = data.shortName
viewHolder.itemView.tag = data
if(isDisplayingQuery(data)) displayQuery(data, false)
}
bindNonModelView = { viewHolder, position ->
}
runOnUiThread = {
requireActivity().runOnUiThread(it)
}
}.build()
list.layoutManager = LinearLayoutManager(requireContext())
list.adapter = adapter
}
private fun displayQuery(dnsQuery: DnsQuery, switchToDetailView:Boolean = true) {
(parentFragment as QueryLogFragment).displayQueryDetailed(dnsQuery, switchToDetailView)
}
private fun isDisplayingQuery(dnsQuery: DnsQuery):Boolean {
val parent = parentFragment as QueryLogFragment
if(!parent.detailFragment.isShowingQuery()) return false
return parent.detailFragment.currentQuery?.id == dnsQuery.id
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:id="@+id/queryTime"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:id="@+id/latency"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:id="@+id/longName"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:id="@+id/type"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:id="@+id/askedServer"
android:layout_height="wrap_content"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
app:tabSelectedTextColor="?attr/inputElementColor"
app:tabIndicatorColor="?attr/inputElementColor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="scrollable"/>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment