process text implementation

This commit is contained in:
Jonathan Fisher 2020-11-09 19:30:53 +00:00
parent 19bbd1e303
commit 29f1ccc00e
12 changed files with 124 additions and 48 deletions

View File

@ -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

View File

@ -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'

View File

@ -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

View File

@ -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" />

View File

@ -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 {

View File

@ -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{

View File

@ -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)
}
} }

View File

@ -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()
}
}
}

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>