diff --git a/app/src/main/java/oppen/Extensions.kt b/app/src/main/java/oppen/Extensions.kt index df4ecd2..6d7f068 100644 --- a/app/src/main/java/oppen/Extensions.kt +++ b/app/src/main/java/oppen/Extensions.kt @@ -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 diff --git a/app/src/main/java/oppen/tva/io/GeminiDatasource.kt b/app/src/main/java/oppen/tva/io/GeminiDatasource.kt index 61a0dc6..7958a4d 100644 --- a/app/src/main/java/oppen/tva/io/GeminiDatasource.kt +++ b/app/src/main/java/oppen/tva/io/GeminiDatasource.kt @@ -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() + 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() } } \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/io/GeminiResponse.kt b/app/src/main/java/oppen/tva/io/GeminiResponse.kt new file mode 100644 index 0000000..062f25c --- /dev/null +++ b/app/src/main/java/oppen/tva/io/GeminiResponse.kt @@ -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) +} \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/io/RuntimeCache.kt b/app/src/main/java/oppen/tva/io/RuntimeCache.kt new file mode 100644 index 0000000..3d11451 --- /dev/null +++ b/app/src/main/java/oppen/tva/io/RuntimeCache.kt @@ -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>>(CACHE_SIZE) + + fun put(uri: URI, header: GeminiResponse.Header, lines: List){ + lruCache.put(uri.toString(), Pair(header, lines)) + } + + fun get(uri: URI): Pair>? = lruCache[uri.toString()] +} \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/io/TvaState.kt b/app/src/main/java/oppen/tva/io/TvaState.kt index 8875faf..30033f9 100644 --- a/app/src/main/java/oppen/tva/io/TvaState.kt +++ b/app/src/main/java/oppen/tva/io/TvaState.kt @@ -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) : TvaState() + + data class ResponseGemtext(val uri: URI, val header: GeminiResponse.Header, val lines: List) : 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() } \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/ui/TvaActivity.kt b/app/src/main/java/oppen/tva/ui/TvaActivity.kt index 41b911d..ca09748 100644 --- a/app/src/main/java/oppen/tva/ui/TvaActivity.kt +++ b/app/src/main/java/oppen/tva/ui/TvaActivity.kt @@ -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 { diff --git a/app/src/main/java/oppen/tva/ui/TvaViewModel.kt b/app/src/main/java/oppen/tva/ui/TvaViewModel.kt index 0a31620..56a2a0c 100644 --- a/app/src/main/java/oppen/tva/ui/TvaViewModel.kt +++ b/app/src/main/java/oppen/tva/ui/TvaViewModel.kt @@ -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)) } } \ No newline at end of file diff --git a/app/src/main/java/oppen/tva/ui/overflow/OverflowPopup.kt b/app/src/main/java/oppen/tva/ui/overflow/OverflowPopup.kt index bd0f29e..9f1e721 100644 --- a/app/src/main/java/oppen/tva/ui/overflow/OverflowPopup.kt +++ b/app/src/main/java/oppen/tva/ui/overflow/OverflowPopup.kt @@ -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() } } diff --git a/app/src/main/java/oppen/tva/ui/set_home/SetHome.kt b/app/src/main/java/oppen/tva/ui/set_home/SetHome.kt new file mode 100644 index 0000000..b4069d2 --- /dev/null +++ b/app/src/main/java/oppen/tva/ui/set_home/SetHome.kt @@ -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() + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/vector_home.xml b/app/src/main/res/drawable/vector_home.xml index 3a4c7da..881ab42 100644 --- a/app/src/main/res/drawable/vector_home.xml +++ b/app/src/main/res/drawable/vector_home.xml @@ -1,10 +1,25 @@ + 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"/> + + + + + diff --git a/app/src/main/res/layout/dialog_set_home.xml b/app/src/main/res/layout/dialog_set_home.xml new file mode 100644 index 0000000..7d88f0d --- /dev/null +++ b/app/src/main/res/layout/dialog_set_home.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/gemtext_code_block.xml b/app/src/main/res/layout/gemtext_code_block.xml index 21d2ff7..f5dbc8f 100644 --- a/app/src/main/res/layout/gemtext_code_block.xml +++ b/app/src/main/res/layout/gemtext_code_block.xml @@ -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" /> \ No newline at end of file diff --git a/app/src/main/res/layout/gemtext_h1.xml b/app/src/main/res/layout/gemtext_h1.xml index 7b6ac2d..d991308 100644 --- a/app/src/main/res/layout/gemtext_h1.xml +++ b/app/src/main/res/layout/gemtext_h1.xml @@ -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" /> \ No newline at end of file diff --git a/app/src/main/res/layout/gemtext_h2.xml b/app/src/main/res/layout/gemtext_h2.xml index 8d7a62b..4e5f841 100644 --- a/app/src/main/res/layout/gemtext_h2.xml +++ b/app/src/main/res/layout/gemtext_h2.xml @@ -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" /> \ No newline at end of file diff --git a/app/src/main/res/layout/gemtext_h3.xml b/app/src/main/res/layout/gemtext_h3.xml index 989f1ff..44b16f6 100644 --- a/app/src/main/res/layout/gemtext_h3.xml +++ b/app/src/main/res/layout/gemtext_h3.xml @@ -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" /> \ No newline at end of file diff --git a/app/src/main/res/layout/gemtext_link.xml b/app/src/main/res/layout/gemtext_link.xml index 98bd5a3..0e9aeaa 100644 --- a/app/src/main/res/layout/gemtext_link.xml +++ b/app/src/main/res/layout/gemtext_link.xml @@ -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" /> \ No newline at end of file diff --git a/app/src/main/res/layout/gemtext_text.xml b/app/src/main/res/layout/gemtext_text.xml index dffb12e..d0adfe0 100644 --- a/app/src/main/res/layout/gemtext_text.xml +++ b/app/src/main/res/layout/gemtext_text.xml @@ -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" /> \ No newline at end of file diff --git a/app/src/main/res/menu/link_menu.xml b/app/src/main/res/menu/link_menu.xml index 29de5bf..465e40a 100644 --- a/app/src/main/res/menu/link_menu.xml +++ b/app/src/main/res/menu/link_menu.xml @@ -2,6 +2,4 @@ - diff --git a/app/src/main/res/menu/overflow_menu.xml b/app/src/main/res/menu/overflow_menu.xml index dd2055b..68b0573 100644 --- a/app/src/main/res/menu/overflow_menu.xml +++ b/app/src/main/res/menu/overflow_menu.xml @@ -1,5 +1,15 @@ - + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index c40158e..a49a04c 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -1,6 +1,6 @@ - #FFFFFF + #ffffff #B8B8B8 #03DAC5 #000000 diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 8ab9164..d5a0088 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,7 +1,7 @@ - #FFFFFF - #B8B8B8 + #ffffff + #1d1d1d #03DAC5 #efefef \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3ac1d84..8d678b0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -4,7 +4,8 @@ Open in new tab Copy address About - Link copied to clipboard + Address copied to clipboard Gemini address Share + Set home \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 6c2e593..ef394a4 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -14,4 +14,6 @@