QueryLogListFragment.kt 5.86 KB
Newer Older
1
2
3
package com.frostnerd.smokescreen.fragment.querylogfragment

import android.os.Bundle
Daniel Wolf's avatar
Daniel Wolf committed
4
5
6
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
7
import android.widget.TextView
8
import androidx.appcompat.widget.SearchView
9
10
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
11
12
import androidx.recyclerview.widget.RecyclerView
import com.frostnerd.cacheadapter.DefaultViewHolder
13
import com.frostnerd.cacheadapter.ModelAdapterBuilder
14
import com.frostnerd.dnstunnelproxy.QueryListener
15
import com.frostnerd.lifecyclemanagement.launchWithLifecycle
16
17
18
import com.frostnerd.smokescreen.R
import com.frostnerd.smokescreen.database.entities.DnsQuery
import com.frostnerd.smokescreen.database.getDatabase
19
import com.frostnerd.smokescreen.equalsAny
20
21
22
import com.frostnerd.smokescreen.fragment.QueryLogFragment
import com.frostnerd.smokescreen.util.LiveDataSource
import kotlinx.android.synthetic.main.fragment_querylog_list.*
23
import kotlinx.android.synthetic.main.item_logged_query.view.*
24
25
26
import org.minidns.record.A
import org.minidns.record.AAAA
import org.minidns.record.Record
27

Daniel Wolf's avatar
Daniel Wolf committed
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
 * Copyright (C) 2019 Daniel Wolf (Ch4t4r)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * You can contact the developer at daniel.wolf@frostnerd.com.
45
 */
46
47
48
49
class QueryLogListFragment: Fragment(), SearchView.OnQueryTextListener {
    private lateinit var unfilteredAdapter:RecyclerView.Adapter<*>
    private var currentSearchText:String? = null

50
51
52
53
54
    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?) {
55
56
57
        launchWithLifecycle(false) {
            val live = requireContext().getDatabase().dnsQueryDao().getAllLive()
            unfilteredAdapter = createAdapter(LiveDataSource(this@QueryLogListFragment, live, true))
58

59
60
61
62
63
64
            launchWithLifecycle(true) {
                list.layoutManager = LinearLayoutManager(requireContext())
                list.adapter = unfilteredAdapter
                progress.visibility = View.GONE
            }
        }
65
66
67
68
    }

    private fun createAdapter(source:LiveDataSource<DnsQuery>): RecyclerView.Adapter<DefaultViewHolder> {
        return ModelAdapterBuilder.newBuilder(source) {
69
70
71
72
73
74
75
76
77
78
79
80
81
            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
82
83
                viewHolder.itemView.typeImage.setImageResource(
                    when (data.responseSource) {
84
                        QueryListener.Source.UPSTREAM ->
85
86
                            if (data.getParsedResponses().any {
                                    (it.type == Record.TYPE.A && (it.payload as A).toString() == "0.0.0.0"
87
                                            || (it.type == Record.TYPE.AAAA && (it.payload as AAAA).toString().equalsAny("::1", "::0", "0:0:0:0:0:0:0:0", "0:0:0:0:0:0:0:1")))
88
                                }) R.drawable.ic_flag
89
90
91
92
                            else R.drawable.ic_reply
                        QueryListener.Source.CACHE, QueryListener.Source.CACHE_AND_LOCALRESOLVER -> R.drawable.ic_database
                        QueryListener.Source.LOCALRESOLVER -> R.drawable.ic_flag
                        else -> R.drawable.ic_query_question
93
94
95
                    }
                )
                if (isDisplayingQuery(data)) displayQuery(data, false)
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
            }
            bindNonModelView = { viewHolder, position ->

            }
            runOnUiThread = {
                requireActivity().runOnUiThread(it)
            }
        }.build()
    }

    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
    }
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132

    override fun onQueryTextSubmit(query: String?): Boolean {
        if(!query.isNullOrBlank() && query != currentSearchText) {
            val live = requireContext().getDatabase().dnsQueryDao().getAllWithHostLive(query)
            val source = LiveDataSource(this, live, true)
            list.adapter = createAdapter(source)
            currentSearchText = query
        } else if(query.isNullOrBlank() && !currentSearchText.isNullOrBlank()) {
            list.adapter = unfilteredAdapter
            currentSearchText = null
        }
        return true
    }

    override fun onQueryTextChange(newText: String?): Boolean {
        if(newText.isNullOrBlank() && !currentSearchText.isNullOrBlank()) onQueryTextSubmit(newText)
        return false
    }
133
}