mirror of https://git.sr.ht/~oppen/ariane
process text implementation
This commit is contained in:
parent
19bbd1e303
commit
29f1ccc00e
|
@ -10,7 +10,8 @@ A Gemini protocol browser for Android based OS. Formerly called Två, and briefl
|
||||||
|
|
||||||
## Releases
|
## Releases
|
||||||
|
|
||||||
See the project page on Öppenlab.net for latest download: [oppenlab.net/pr/ariane](https://oppenlab.net/pr/ariane/)
|
* See the project page on Öppenlab.net for latest download: [oppenlab.net/pr/ariane](https://oppenlab.net/pr/ariane/)
|
||||||
|
* Install on [Google Play](https://play.google.com/store/apps/details?id=oppen.gemini.ariane)
|
||||||
|
|
||||||
## Issue tracker
|
## Issue tracker
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,6 @@ dependencies {
|
||||||
kapt "androidx.room:room-compiler:$room_version"
|
kapt "androidx.room:room-compiler:$room_version"
|
||||||
implementation "androidx.room:room-ktx:$room_version"
|
implementation "androidx.room:room-ktx:$room_version"
|
||||||
|
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.13'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
|
||||||
|
|
|
@ -18,4 +18,19 @@
|
||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
# If you keep the line number information, uncomment this to
|
||||||
# hide the original source file name.
|
# hide the original source file name.
|
||||||
#-renamesourcefileattribute SourceFile
|
#-renamesourcefileattribute SourceFile
|
||||||
|
|
||||||
|
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||||
|
-keep class * extends com.bumptech.glide.module.AppGlideModule {
|
||||||
|
<init>(...);
|
||||||
|
}
|
||||||
|
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
|
||||||
|
**[] $VALUES;
|
||||||
|
public *;
|
||||||
|
}
|
||||||
|
-keep class com.bumptech.glide.load.data.ParcelFileDescriptorRewinder$InternalRewinder {
|
||||||
|
*** rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
# for DexGuard only
|
||||||
|
# -keepresourcexmlelements manifest/application/meta-data@value=GlideModule
|
|
@ -14,17 +14,19 @@
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:networkSecurityConfig="@xml/network_security_config">
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
|
<activity android:name="oppen.ariane.ui.ProcessTextActivity" android:label="Open in Ariane" android:launchMode="singleTop">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||||
|
<data android:mimeType="text/plain"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<activity android:name="oppen.ariane.ui.GemActivity"
|
<activity android:name="oppen.ariane.ui.GemActivity"
|
||||||
android:label="Open in Ariane">
|
android:launchMode="singleTop">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<data android:mimeType="text/plain" />
|
|
||||||
</intent-filter>
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
|
|
@ -193,7 +193,7 @@ class GeminiDatasource(val context: Context): Datasource {
|
||||||
val bufferedReader = BufferedReader(headerInputReader)
|
val bufferedReader = BufferedReader(headerInputReader)
|
||||||
val headerLine = bufferedReader.readLine()
|
val headerLine = bufferedReader.readLine()
|
||||||
|
|
||||||
println("Tva: header: $headerLine")
|
println("Ariane: response header: $headerLine")
|
||||||
|
|
||||||
val header = GeminiResponse.parseHeader(headerLine)
|
val header = GeminiResponse.parseHeader(headerLine)
|
||||||
|
|
||||||
|
@ -246,8 +246,6 @@ class GeminiDatasource(val context: Context): Datasource {
|
||||||
val filenameRegex = Regex("[^A-Za-z0-9]")
|
val filenameRegex = Regex("[^A-Za-z0-9]")
|
||||||
val cacheFile = File(context.cacheDir, filenameRegex.replace(uri.path, "_"))
|
val cacheFile = File(context.cacheDir, filenameRegex.replace(uri.path, "_"))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
when {
|
when {
|
||||||
cacheFile.exists() -> {
|
cacheFile.exists() -> {
|
||||||
when {
|
when {
|
||||||
|
|
|
@ -55,10 +55,13 @@ class GemActivity : AppCompatActivity() {
|
||||||
private val model by viewModels<GemViewModel>()
|
private val model by viewModels<GemViewModel>()
|
||||||
private lateinit var binding: ActivityGemBinding
|
private lateinit var binding: ActivityGemBinding
|
||||||
private lateinit var history: HistoryInterface
|
private lateinit var history: HistoryInterface
|
||||||
private val adapter = GemtextAdapter { uri, longTap, view ->
|
private val adapter = GemtextAdapter { adapter, uri, longTap, position: Int, view ->
|
||||||
if(longTap){
|
if(longTap){
|
||||||
LinkPopup.show(view){ menuId ->
|
LinkPopup.show(view, uri){ menuId ->
|
||||||
when (menuId) {
|
when (menuId) {
|
||||||
|
R.id.link_menu_load_image -> {
|
||||||
|
adapter.loadImage(position)
|
||||||
|
}
|
||||||
R.id.link_menu_copy -> {
|
R.id.link_menu_copy -> {
|
||||||
Intent().apply {
|
Intent().apply {
|
||||||
action = Intent.ACTION_SEND
|
action = Intent.ACTION_SEND
|
||||||
|
@ -219,7 +222,15 @@ class GemActivity : AppCompatActivity() {
|
||||||
model.request(address)
|
model.request(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkIntentExtras()
|
checkIntentExtras(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent?) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
|
||||||
|
intent?.let{
|
||||||
|
checkIntentExtras(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -227,39 +238,23 @@ class GemActivity : AppCompatActivity() {
|
||||||
* Checks intent to see if Activity was opened to handle selected text
|
* Checks intent to see if Activity was opened to handle selected text
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private fun checkIntentExtras() {
|
private fun checkIntentExtras(intent: Intent) {
|
||||||
|
|
||||||
//First check if there's a uri from a web link or other
|
//Via ProcessTextActivity from selected text in another app
|
||||||
|
if(intent.hasExtra("process_text")){
|
||||||
|
val processText = intent.getStringExtra("process_text")
|
||||||
|
binding.addressEdit.setText(processText)
|
||||||
|
model.request(processText ?: "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//From clicking a gemini:// address
|
||||||
val uri = intent.data
|
val uri = intent.data
|
||||||
if(uri != null){
|
if(uri != null){
|
||||||
binding.addressEdit.setText(uri.toString())
|
binding.addressEdit.setText(uri.toString())
|
||||||
model.request(uri.toString())
|
model.request(uri.toString())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//Then check if we've arrived here via some selected text
|
|
||||||
val processText = when {
|
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
|
||||||
intent.hasExtra(Intent.EXTRA_PROCESS_TEXT) -> {
|
|
||||||
intent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT).toString()
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
processText?.let { text ->
|
|
||||||
if (text.startsWith("gemini://")) {
|
|
||||||
binding.addressEdit.setText(text)
|
|
||||||
model.request(text)
|
|
||||||
} else {
|
|
||||||
Snackbar.make(binding.root, "$text is not a valid Gemini address", Snackbar.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent?) {
|
|
||||||
super.onNewIntent(intent)
|
|
||||||
intent?.data.toString().let{model.request(it)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showAlert(message: String) = runOnUiThread{
|
private fun showAlert(message: String) = runOnUiThread{
|
||||||
|
|
|
@ -9,12 +9,15 @@ import kotlinx.android.synthetic.main.gemtext_code_block.view.*
|
||||||
import kotlinx.android.synthetic.main.gemtext_link.view.*
|
import kotlinx.android.synthetic.main.gemtext_link.view.*
|
||||||
import kotlinx.android.synthetic.main.gemtext_text.view.gemtext_text_textview
|
import kotlinx.android.synthetic.main.gemtext_text.view.gemtext_text_textview
|
||||||
import oppen.ariane.R
|
import oppen.ariane.R
|
||||||
|
import oppen.visible
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
|
||||||
class GemtextAdapter(val onLink: (link: URI, longTap: Boolean, view: View?) -> Unit): RecyclerView.Adapter<GemtextAdapter.ViewHolder>() {
|
class GemtextAdapter(val onLink: (adapter: GemtextAdapter, link: URI, longTap: Boolean, adapterPosition: Int, view: View?) -> Unit): RecyclerView.Adapter<GemtextAdapter.ViewHolder>() {
|
||||||
|
|
||||||
var lines = mutableListOf<String>()
|
var lines = mutableListOf<String>()
|
||||||
|
|
||||||
|
var imageIndexes = arrayListOf<Int>()
|
||||||
|
|
||||||
private val typeText = 0
|
private val typeText = 0
|
||||||
private val typeH1 = 1
|
private val typeH1 = 1
|
||||||
private val typeH2 = 2
|
private val typeH2 = 2
|
||||||
|
@ -110,14 +113,21 @@ class GemtextAdapter(val onLink: (link: URI, longTap: Boolean, view: View?) -> U
|
||||||
holder.itemView.gemtext_text_link.setOnClickListener {
|
holder.itemView.gemtext_text_link.setOnClickListener {
|
||||||
val uri = getUri(lines[holder.adapterPosition])
|
val uri = getUri(lines[holder.adapterPosition])
|
||||||
println("User click link: $uri")
|
println("User click link: $uri")
|
||||||
onLink(uri, false, null)
|
onLink(this, uri, false, holder.adapterPosition, null)
|
||||||
}
|
}
|
||||||
holder.itemView.gemtext_text_link.setOnLongClickListener {view ->
|
holder.itemView.gemtext_text_link.setOnLongClickListener {view ->
|
||||||
val uri = getUri(lines[holder.adapterPosition])
|
val uri = getUri(lines[holder.adapterPosition])
|
||||||
println("User click link: $uri")
|
println("User click link: $uri")
|
||||||
onLink(uri, true, view)
|
onLink(this, uri, true, holder.adapterPosition, view)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(imageIndexes.contains(holder.adapterPosition)){
|
||||||
|
holder.itemView.gemtext_inline_image.visible(true)
|
||||||
|
|
||||||
|
//todo - need to download the image...
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,4 +144,9 @@ class GemtextAdapter(val onLink: (link: URI, longTap: Boolean, view: View?) -> U
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun loadImage(position: Int){
|
||||||
|
imageIndexes.add(position)
|
||||||
|
notifyItemChanged(position)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package oppen.ariane.ui
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
|
||||||
|
class ProcessTextActivity: AppCompatActivity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
val processText = when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && intent.hasExtra(Intent.EXTRA_PROCESS_TEXT) -> intent.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT).toString()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent(this, GemActivity::class.java).run {
|
||||||
|
putExtra("process_text", processText)
|
||||||
|
startActivity(this)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,15 +4,23 @@ import android.view.MenuInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import oppen.ariane.R
|
import oppen.ariane.R
|
||||||
|
import java.net.URI
|
||||||
|
|
||||||
|
|
||||||
object LinkPopup {
|
object LinkPopup {
|
||||||
|
|
||||||
fun show(view: View?, onMenuOption: (menuId: Int) -> Unit){
|
fun show(view: View?, uri: URI, onMenuOption: (menuId: Int) -> Unit){
|
||||||
if(view != null) {
|
if(view != null) {
|
||||||
val popup = PopupMenu(view.context, view)
|
val popup = PopupMenu(view.context, view)
|
||||||
val inflater: MenuInflater = popup.menuInflater
|
val inflater: MenuInflater = popup.menuInflater
|
||||||
inflater.inflate(R.menu.link_menu, popup.menu)
|
|
||||||
|
val path = uri.toString().toLowerCase()
|
||||||
|
if(path.endsWith(".png") || path.endsWith(".jpg") || path.endsWith(".jpeg")){
|
||||||
|
inflater.inflate(R.menu.image_link_menu, popup.menu)
|
||||||
|
}else{
|
||||||
|
inflater.inflate(R.menu.link_menu, popup.menu)
|
||||||
|
}
|
||||||
|
|
||||||
popup.setOnMenuItemClickListener { menuItem ->
|
popup.setOnMenuItemClickListener { menuItem ->
|
||||||
onMenuOption(menuItem.itemId)
|
onMenuOption(menuItem.itemId)
|
||||||
true
|
true
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.appcompat.widget.AppCompatTextView
|
<RelativeLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
<androidx.appcompat.widget.AppCompatTextView
|
||||||
android:id="@+id/gemtext_text_link"
|
android:id="@+id/gemtext_text_link"
|
||||||
android:textColor="@color/stroke"
|
android:textColor="@color/stroke"
|
||||||
android:textSize="@dimen/default_text_size"
|
android:textSize="@dimen/default_text_size"
|
||||||
|
@ -10,4 +13,12 @@
|
||||||
android:layout_marginLeft="@dimen/screen_margin"
|
android:layout_marginLeft="@dimen/screen_margin"
|
||||||
android:layout_marginRight="@dimen/screen_margin"
|
android:layout_marginRight="@dimen/screen_margin"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/gemtext_inline_image"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_below="@+id/gemtext_text_link"/>
|
||||||
|
</RelativeLayout>
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:id="@+id/link_menu_load_image"
|
||||||
|
android:title="@string/load_image" />
|
||||||
|
<item android:id="@+id/link_menu_copy"
|
||||||
|
android:title="@string/copy_address" />
|
||||||
|
</menu>
|
|
@ -4,6 +4,7 @@
|
||||||
<string name="main_input_hint">Enter gemini:// address</string>
|
<string name="main_input_hint">Enter gemini:// address</string>
|
||||||
<string name="main_input_search_hint">Enter search term</string>
|
<string name="main_input_search_hint">Enter search term</string>
|
||||||
<string name="copy_address">Copy address</string>
|
<string name="copy_address">Copy address</string>
|
||||||
|
<string name="load_image">Load image</string>
|
||||||
<string name="about">About</string>
|
<string name="about">About</string>
|
||||||
<string name="address_copied_to_clipboard">Address copied to clipboard</string>
|
<string name="address_copied_to_clipboard">Address copied to clipboard</string>
|
||||||
<string name="gemini_address">Gemini address</string>
|
<string name="gemini_address">Gemini address</string>
|
||||||
|
|
Loading…
Reference in New Issue