numerous fixes

This commit is contained in:
Öppen 2020-08-18 17:17:04 +01:00
parent 4ea369610a
commit e58deb28c3
23 changed files with 293 additions and 87 deletions

View File

@ -1,16 +1,7 @@
package oppen
import android.app.AlertDialog
import android.content.Context
import android.view.View
fun String.alert(context: Context){
AlertDialog.Builder(context)
.setMessage(this)
.setPositiveButton("OK"){_, _ ->}
.show()
}
fun View.visible(visible: Boolean) = when {
visible -> this.visibility = View.VISIBLE
else -> this.visibility = View.GONE

View File

@ -22,39 +22,50 @@ class GeminiDatasource: Datasource{
when (uri.scheme) {
GEMINI_SCHEME -> {
//Indicate app should show progress indicator
onUpdate(TvaState.Requesting(uri))
GlobalScope.launch {
geminiRequest(uri, onUpdate)
val cached = RuntimeCache.get(uri)
if(cached != null){
last = uri
onUpdate(TvaState.ResponseGemtext(uri, cached.first, cached.second))
return
}else{
onUpdate(TvaState.Requesting(uri))
GlobalScope.launch {
geminiRequest(uri, onUpdate)
}
}
}
else -> {
val address = uri.toString()
when {
val parsedUri = when {
address.startsWith("//") -> {
//just missing protocol
onUpdate(TvaState.Requesting(uri))
request(URI.create("gemini:$address"), onUpdate)
return
URI.create("gemini:$address")
}
address.startsWith("/") -> {
//internal navigation
val internalNav = "gemini://${last?.host}$address"
onUpdate(TvaState.Requesting(uri))
request(URI.create(internalNav), onUpdate)
return
URI.create(internalNav)
}
!address.contains("://") -> {
//looks like a relative link
val lastAddress = last.toString()
val relAddress = "${lastAddress.substring(0, lastAddress.lastIndexOf("/") + 1)}$address"
onUpdate(TvaState.Requesting(uri))
request(URI.create(relAddress), onUpdate)
URI.create(relAddress)
}
else -> {
onUpdate(TvaState.NotGeminiRequest(uri))
return
}
else -> onUpdate(TvaState.NotGeminiRequest(uri))
}
val cached = RuntimeCache.get(parsedUri)
if(cached != null){
last = parsedUri
onUpdate(TvaState.ResponseGemtext(parsedUri, cached.first, cached.second))
}else{
request(parsedUri, onUpdate)
}
}
}
@ -87,31 +98,56 @@ class GeminiDatasource: Datasource{
outWriter.flush()
if (outWriter.checkError()) {
onUpdate(TvaState.GeminiPrintWriterError)
onUpdate(TvaState.ResponseError(GeminiResponse.Header(-1, "Print Writer Error")))
outWriter.close()
return
}
outputStreamWriter.close()
bufferedWriter.close()
outWriter.close()
// IN <<<<<<<<<<<<<<<<<<<<<<<<<<<
var headerLine = ""
InputStreamReader(socket.inputStream).use{ streamReader ->
BufferedReader(streamReader).use{ bufferedReader ->
headerLine = bufferedReader.readLine()
}
}
println("Tva: header: $headerLine")
val header = GeminiResponse.parseHeader(headerLine)
when {
header.code != GeminiResponse.SUCCESS -> onUpdate(TvaState.ResponseError(header))
header.meta == "text/gemini" -> getGemtext(socket, uri, header, onUpdate)
header.meta.startsWith("text/") -> getString(socket, uri, header, onUpdate)
else -> onUpdate(TvaState.ResponseError(header))
}
}
private fun getGemtext(socket: SSLSocket, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){
val lines = mutableListOf<String>()
socket.inputStream.reader().use { inputStreamReader ->
BufferedReader(inputStreamReader).use { reader ->
lines.addAll(reader.readLines())
}
}
val header = lines.firstOrNull() ?: ""
lines.removeAt(0)
socket.close()
println("Tva: header: $header")
val processed = GemtextHelper.findCodeBlocks(lines)
RuntimeCache.put(uri, header, processed)
onUpdate(TvaState.ResponseGemtext(uri, header, processed))
}
outputStreamWriter.close()
bufferedWriter.close()
outWriter.close()
private fun getString(socket: SSLSocket, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){
val content = socket.inputStream.bufferedReader().use { reader -> reader.readText() }
onUpdate(TvaState.GeminiResponse(uri, header, GemtextHelper.findCodeBlocks(lines)))
socket.close()
}
}

View File

@ -0,0 +1,32 @@
package oppen.tva.io
object GeminiResponse {
const val INPUT = 1
const val SUCCESS = 2
const val REDIRECT = 3
const val TEMPORARY_FAILURE = 4
const val PERMANENT_FAILURE = 5
const val CLIENT_CERTIFICATE_REQUIRED = 6
const val UNKNOWN = -1
fun parseHeader(header: String): Header{
val segments = header.trim().split(" ")
val meta = if(segments.size > 1){
segments[1]
}else{
"No meta/mime type"
}
return when {
segments.first().startsWith("1") -> Header(INPUT, meta)
segments.first().startsWith("2") -> Header(SUCCESS, meta)
segments.first().startsWith("3") -> Header(REDIRECT, meta)
segments.first().startsWith("4") -> Header(TEMPORARY_FAILURE, meta)
segments.first().startsWith("5") -> Header(PERMANENT_FAILURE, meta)
segments.first().startsWith("6") -> Header(CLIENT_CERTIFICATE_REQUIRED, meta)
else -> Header(UNKNOWN, meta)
}
}
class Header(val code: Int, val meta: String)
}

View File

@ -0,0 +1,16 @@
package oppen.tva.io
import androidx.collection.LruCache
import java.net.URI
object RuntimeCache {
private const val CACHE_SIZE = 4 * 1024 * 1024
private val lruCache = LruCache<String, Pair<GeminiResponse.Header, List<String>>>(CACHE_SIZE)
fun put(uri: URI, header: GeminiResponse.Header, lines: List<String>){
lruCache.put(uri.toString(), Pair(header, lines))
}
fun get(uri: URI): Pair<GeminiResponse.Header, List<String>>? = lruCache[uri.toString()]
}

View File

@ -6,8 +6,11 @@ sealed class TvaState {
data class AppQuery(val uri: URI): TvaState()
data class Requesting(val uri: URI): TvaState()
data class NotGeminiRequest(val uri: URI) : TvaState()
data class GeminiResponse(val uri: URI, val header: String, val lines: List<String>) : TvaState()
data class ResponseGemtext(val uri: URI, val header: GeminiResponse.Header, val lines: List<String>) : TvaState()
data class ResponseText(val uri: URI, val header: GeminiResponse.Header, val content: String) : TvaState()
data class ResponseError(val header: GeminiResponse.Header): TvaState()
data class TabChange(val count: Int) : TvaState()
object Blank: TvaState()
object GeminiPrintWriterError : TvaState()
}

View File

@ -1,8 +1,8 @@
package oppen.tva.ui
import android.R.attr.label
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
@ -12,11 +12,12 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import oppen.alert
import oppen.tva.R
import oppen.tva.databinding.ActivityTvaBinding
import oppen.tva.io.TvaState
import oppen.tva.io.history.CacheInterface
import oppen.tva.ui.overflow.OverflowPopup
import oppen.tva.ui.set_home.SetHome
import oppen.tva.ui.tabs.NewTabPopup
import oppen.tva.ui.tabs.TabsDialog
import oppen.visibleRetainingSpace
@ -33,19 +34,6 @@ class TvaActivity : AppCompatActivity() {
R.id.link_menu_open_in_new_tab -> {
model.newTab(uri)
}
R.id.link_menu_copy -> {
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.gemini_address), uri.toString())
clipboard.setPrimaryClip(clip)
Snackbar.make(binding.root, getString(R.string.address_copied_to_clipboard), Snackbar.LENGTH_SHORT).setAction(R.string.share) {
Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, uri.toString())
type = "text/plain"
startActivity(Intent.createChooser(this, null))
}
}.show()
}
}
}
}else{
@ -65,16 +53,17 @@ class TvaActivity : AppCompatActivity() {
model.initialise(CacheInterface.default(this)){ state ->
when(state){
is TvaState.AppQuery -> TODO()
is TvaState.AppQuery -> runOnUiThread{ showAlert("App backdoor/query not implemented yet") }
is TvaState.Requesting -> loadingView(true)
is TvaState.NotGeminiRequest -> externalProtocol(state)
is TvaState.GeminiResponse -> renderGemtext(state)
is TvaState.ResponseError -> showAlert("${state.header.code}: ${state.header.meta}")
is TvaState.ResponseGemtext -> renderGemtext(state)
is TvaState.ResponseText -> runOnUiThread{ showAlert("Plain text display not implemented") }
is TvaState.TabChange -> binding.tabCount.text = "${state.count}"
is TvaState.Blank -> {
binding.addressEdit.setText("")
adapter.render(arrayListOf())
}
TvaState.GeminiPrintWriterError -> "Error with socket writer".alert(this)
}
}
@ -88,27 +77,66 @@ class TvaActivity : AppCompatActivity() {
}
}
binding.more.setOnClickListener { "Not implemented yet".alert(this) }
binding.home.setOnClickListener { "Not implemented yet".alert(this) }
binding.more.setOnClickListener {
OverflowPopup.show(binding.more){menuId ->
when (menuId) {
R.id.overflow_menu_share -> {
Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, binding.addressEdit.text.toString())
type = "text/plain"
startActivity(Intent.createChooser(this, null))
}
}
R.id.overflow_menu_about -> {
}
R.id.overflow_menu_set_home -> {
SetHome.show(this, binding.addressEdit.text.toString()){
showAlert("Home capsule updated")
}
}
R.id.overflow_menu_copy -> {
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText(getString(R.string.gemini_address), binding.addressEdit.text.toString())
clipboard.setPrimaryClip(clip)
Snackbar.make(binding.root, getString(R.string.address_copied_to_clipboard), Snackbar.LENGTH_SHORT).setAction(R.string.share) {
Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, binding.addressEdit.text.toString())
type = "text/plain"
startActivity(Intent.createChooser(this, null))
}
}.show()
}
}
}
}
binding.home.setOnClickListener {
val prefs = getSharedPreferences("oppen.tva.ui.set_home", Context.MODE_PRIVATE)
val home = prefs.getString("home", "gemini://gemini.circumlunar.space/")
model.request(home!!)
}
binding.tabs.setOnClickListener {
TabsDialog().show(this, model)
}
}
private fun externalProtocol(state: TvaState.NotGeminiRequest) {
private fun showAlert(message: String) = runOnUiThread{
loadingView(false)
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
}
private fun externalProtocol(state: TvaState.NotGeminiRequest) = runOnUiThread {
loadingView(false)
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(state.uri.toString()))
startActivity(browserIntent)
}
private fun renderGemtext(state: TvaState.GeminiResponse) = runOnUiThread {
private fun renderGemtext(state: TvaState.ResponseGemtext) = runOnUiThread {
loadingView(false)
if(state.header.startsWith("2") && state.header.contains("text/gemini")) {
binding.addressEdit.setText(state.uri.toString())
adapter.render(state.lines)
}else{
"Server returned an error - or non gemtext mimetype not implemented yet: ${state.header}".alert(this)
}
binding.addressEdit.setText(state.uri.toString())
adapter.render(state.lines)
}
private fun loadingView(visible: Boolean) = runOnUiThread {

View File

@ -50,16 +50,17 @@ class TvaViewModel: ViewModel() {
fun request(uri: URI){
gemini.request(uri){ state ->
when(state){
is TvaState.Requesting -> onState(state)
is TvaState.AppQuery -> {}
is TvaState.ResponseGemtext -> renderGemini(state)
is TvaState.Requesting -> onState(state)
is TvaState.ResponseError -> onState(state)
is TvaState.NotGeminiRequest -> onState(state)
is TvaState.GeminiResponse -> renderGemini(state)
TvaState.GeminiPrintWriterError -> onState(state)
is TvaState.ResponseText -> onState(state)
}
}
}
private fun renderGemini(state: TvaState.GeminiResponse) {
private fun renderGemini(state: TvaState.ResponseGemtext) {
if(tabs[activeTab].history.isEmpty() || tabs[activeTab].history.last() != state.uri){
tabs[activeTab].add(state.uri)
}
@ -100,11 +101,9 @@ class TvaViewModel: ViewModel() {
if(deleteIndex > activeTab){
tabs.removeAt(deleteIndex)
onState(TvaState.TabChange(tabs.size))
}else if(deleteIndex < activeTab){
tabs.removeAt(deleteIndex)
activeTab--
onState(TvaState.TabChange(tabs.size))
}else if(deleteIndex == activeTab){
if(tabs.size > 1){
tabs.removeAt(deleteIndex)
@ -120,5 +119,6 @@ class TvaViewModel: ViewModel() {
onState(TvaState.Blank)
}
}
onState(TvaState.TabChange(tabs.size))
}
}

View File

@ -3,9 +3,10 @@ package oppen.tva.ui.overflow
import android.view.MenuInflater
import android.view.View
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.MenuCompat
import oppen.tva.R
class OverflowPopup {
object OverflowPopup {
fun show(view: View?, onMenuOption: (menuId: Int) -> Unit){
if(view != null) {
@ -16,6 +17,7 @@ class OverflowPopup {
onMenuOption(menuItem.itemId)
true
}
MenuCompat.setGroupDividerEnabled(popup.menu, true)
popup.show()
}
}

View File

@ -0,0 +1,37 @@
package oppen.tva.ui.set_home
import android.content.Context
import android.view.View
import androidx.appcompat.app.AppCompatDialog
import kotlinx.android.synthetic.main.dialog_set_home.view.*
import oppen.tva.R
object SetHome {
fun show(context: Context, currentAddress: String, onUpdate: () -> Unit){
val prefs = context.getSharedPreferences("oppen.tva.ui.set_home", Context.MODE_PRIVATE)
val home = prefs.getString("home", "")
val dialog = AppCompatDialog(context, R.style.DayNightDialog)
val view = View.inflate(context, R.layout.dialog_set_home, null)
view.home_edit_text.setText(home)
view.set_home_button.setOnClickListener {
prefs.edit().putString("home", view.home_edit_text.text.toString()).apply()
onUpdate()
dialog.dismiss()
}
view.use_current_button.setOnClickListener {
view.home_edit_text.setText(currentAddress)
}
dialog.setTitle("Set home capsule")
dialog.setContentView(view)
dialog.show()
}
}

View File

@ -1,10 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:height="24.5dp"
android:viewportWidth="48"
android:viewportHeight="49"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z"/>
android:pathData="M47.723,19.3306L24.481,0.1701C24.3393,0.0567 24.1692,0 24.0086,0C23.8385,0 23.6685,0.0567 23.5362,0.1701L11.5845,10.0054V0.7464C11.5845,0.3307 11.2444,0 10.8381,0C10.4318,0 10.0917,0.3401 10.0917,0.7464V11.2431L0.2753,19.3306C-0.046,19.5951 -0.0932,20.0675 0.1713,20.3887C0.4359,20.71 0.9083,20.7572 1.2295,20.4927L4.2056,18.0456V45.0007C4.2056,46.6541 5.5472,48.0052 7.2101,48.0052H40.8071C42.4605,48.0052 43.8115,46.6635 43.8115,45.0007V18.0362L46.7877,20.4832C46.9294,20.5966 47.0994,20.6533 47.2601,20.6533C47.4774,20.6533 47.6947,20.5588 47.8364,20.3793C48.0915,20.0675 48.0442,19.5951 47.723,19.3306ZM35.2422,46.4935H25.2652V34.0977H35.2422V46.4935ZM42.2999,45.0007C42.2999,45.8321 41.6291,46.5029 40.7976,46.5029H36.7445V33.3419C36.7445,32.9262 36.4043,32.5955 35.9981,32.5955H24.5188C24.1031,32.5955 23.7724,32.9356 23.7724,33.3419V46.4935H7.2006C6.3692,46.4935 5.6984,45.8227 5.6984,44.9913V16.7985L23.9991,1.7195L42.2999,16.7985V45.0007Z"
android:fillColor="#000000"/>
<path
android:pathData="M10.8381,34.6646C10.4224,34.6646 10.0917,35.0047 10.0917,35.411V36.6581C10.0917,37.0738 10.4319,37.4045 10.8381,37.4045C11.2444,37.4045 11.5845,37.0644 11.5845,36.6581V35.411C11.5845,34.9953 11.2538,34.6646 10.8381,34.6646Z"
android:fillColor="#000000"/>
<path
android:pathData="M10.8381,38.8029C10.4224,38.8029 10.0917,39.143 10.0917,39.5492V40.7964C10.0917,41.2121 10.4319,41.5428 10.8381,41.5428C11.2444,41.5428 11.5845,41.2026 11.5845,40.7964V39.5492C11.5845,39.143 11.2538,38.8029 10.8381,38.8029Z"
android:fillColor="#000000"/>
<path
android:pathData="M17.2249,34.6646C16.8092,34.6646 16.4785,35.0047 16.4785,35.411V36.6581C16.4785,37.0738 16.8187,37.4045 17.2249,37.4045C17.6312,37.4045 17.9713,37.0644 17.9713,36.6581V35.411C17.9808,34.9953 17.6406,34.6646 17.2249,34.6646Z"
android:fillColor="#000000"/>
<path
android:pathData="M17.2249,38.8029C16.8092,38.8029 16.4785,39.143 16.4785,39.5492V40.7964C16.4785,41.2121 16.8187,41.5428 17.2249,41.5428C17.6312,41.5428 17.9713,41.2026 17.9713,40.7964V39.5492C17.9808,39.143 17.6406,38.8029 17.2249,38.8029Z"
android:fillColor="#000000"/>
<path
android:pathData="M17.2722,16.3072C17.2722,20.0203 20.2861,23.0342 23.9991,23.0342C27.7122,23.0342 30.7261,20.0203 30.7261,16.3072C30.7261,12.5942 27.7122,9.5803 23.9991,9.5803C20.2861,9.5803 17.2722,12.5942 17.2722,16.3072ZM29.2239,16.3072C29.2239,19.1889 26.8808,21.5319 23.9991,21.5319C21.1175,21.5319 18.7744,19.1889 18.7744,16.3072C18.7744,13.4256 21.1175,11.0825 23.9991,11.0825C26.8808,11.0825 29.2239,13.4256 29.2239,16.3072Z"
android:fillColor="#000000"/>
</vector>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:padding="@dimen/default_margin">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/home_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/set_home_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Update"
android:layout_below="@+id/home_edit_text"/>
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/use_current_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="@+id/set_home_button"
android:text="Use current"
android:layout_below="@+id/home_edit_text"/>
</RelativeLayout>

View File

@ -11,5 +11,6 @@
android:paddingBottom="@dimen/default_margin"
android:fontFamily="monospace"
android:background="@color/code_background"
android:textIsSelectable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View File

@ -5,4 +5,5 @@
android:textSize="@dimen/h1_text_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:layout_margin="@dimen/default_margin" />

View File

@ -5,4 +5,5 @@
android:textSize="@dimen/h2_text_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:layout_margin="@dimen/default_margin" />

View File

@ -5,4 +5,5 @@
android:textSize="@dimen/h3_text_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:layout_margin="@dimen/default_margin" />

View File

@ -6,7 +6,7 @@
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:paddingLeft="@dimen/default_margin"
android:paddingRight="@dimen/default_margin"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

View File

@ -5,5 +5,6 @@
android:textSize="@dimen/default_text_size"
android:paddingLeft="@dimen/default_margin"
android:paddingRight="@dimen/default_margin"
android:textIsSelectable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

View File

@ -2,6 +2,4 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/link_menu_open_in_new_tab"
android:title="@string/open_in_new_tab" />
<item android:id="@+id/link_menu_copy"
android:title="@string/copy_address" />
</menu>

View File

@ -1,5 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/overflow_menu_about"
android:title="@string/about" />
<group android:id="@+id/app" >
<item android:id="@+id/overflow_menu_share"
android:title="@string/share" />
<item android:id="@+id/overflow_menu_copy"
android:title="@string/copy_address" />
<item android:id="@+id/overflow_menu_set_home"
android:title="@string/set_home" />
</group>
<group android:id="@+id/other" >
<item android:id="@+id/overflow_menu_about"
android:title="@string/about" />
</group>
</menu>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#FFFFFF</color>
<color name="colorPrimary">#ffffff</color>
<color name="colorPrimaryDark">#B8B8B8</color>
<color name="colorAccent">#03DAC5</color>
<color name="code_background">#000000</color>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#FFFFFF</color>
<color name="colorPrimaryDark">#B8B8B8</color>
<color name="colorPrimary">#ffffff</color>
<color name="colorPrimaryDark">#1d1d1d</color>
<color name="colorAccent">#03DAC5</color>
<color name="code_background">#efefef</color>
</resources>

View File

@ -4,7 +4,8 @@
<string name="open_in_new_tab">Open in new tab</string>
<string name="copy_address">Copy address</string>
<string name="about">About</string>
<string name="address_copied_to_clipboard">Link copied to clipboard</string>
<string name="address_copied_to_clipboard">Address copied to clipboard</string>
<string name="gemini_address">Gemini address</string>
<string name="share">Share</string>
<string name="set_home">Set home</string>
</resources>

View File

@ -14,4 +14,6 @@
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
<style name="DayNightDialog" parent="Theme.AppCompat.DayNight.Dialog.Alert"/>
</resources>