mirror of https://git.sr.ht/~oppen/ariane
fix ./ relative url linking, add inline image feature
This commit is contained in:
parent
e4669d9592
commit
e5a26ce3a2
|
@ -9,6 +9,6 @@ class Ariane: Application() {
|
||||||
const val GEMINI_USER_SEARCH_BASE = "gemini://gus.guru/search?"
|
const val GEMINI_USER_SEARCH_BASE = "gemini://gus.guru/search?"
|
||||||
const val GEMINI_BACKLINK_BASE = "gemini://gus.guru/backlinks?"
|
const val GEMINI_BACKLINK_BASE = "gemini://gus.guru/backlinks?"
|
||||||
|
|
||||||
const val FEATURE_INLINE_IMAGES = false
|
const val FEATURE_INLINE_IMAGES = true
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -22,8 +22,7 @@ const val GEMINI_SCHEME = "gemini"
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class GeminiDatasource(
|
class GeminiDatasource(
|
||||||
private val context: Context
|
private val context: Context): Datasource {
|
||||||
): Datasource {
|
|
||||||
|
|
||||||
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
private var last: URI? = null
|
private var last: URI? = null
|
||||||
|
@ -65,10 +64,15 @@ class GeminiDatasource(
|
||||||
URI.create("gemini:$address")
|
URI.create("gemini:$address")
|
||||||
}
|
}
|
||||||
address.startsWith("/") -> {
|
address.startsWith("/") -> {
|
||||||
//internal navigation
|
//internal navigation/relative link
|
||||||
val internalNav = "gemini://${last?.host}$address"
|
val internalNav = "gemini://${last?.host}$address"
|
||||||
URI.create(internalNav)
|
URI.create(internalNav)
|
||||||
}
|
}
|
||||||
|
address.startsWith("./") -> {
|
||||||
|
//internal navigation/relative link - with dot
|
||||||
|
val internalNav = "gemini://${last?.host}${address.substring(1)}"
|
||||||
|
URI.create(internalNav)
|
||||||
|
}
|
||||||
!address.contains("://") -> {
|
!address.contains("://") -> {
|
||||||
//looks like a relative link
|
//looks like a relative link
|
||||||
val lastAddress = last.toString()
|
val lastAddress = last.toString()
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
package oppen.ariane.ui
|
package oppen.ariane.ui
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException
|
import android.content.ActivityNotFoundException
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.media.MediaPlayer
|
import android.media.MediaPlayer
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
|
@ -35,7 +32,6 @@ import oppen.ariane.ui.modals_menus.about.AboutDialog
|
||||||
import oppen.ariane.ui.modals_menus.history.HistoryDialog
|
import oppen.ariane.ui.modals_menus.history.HistoryDialog
|
||||||
import oppen.ariane.ui.modals_menus.input.InputDialog
|
import oppen.ariane.ui.modals_menus.input.InputDialog
|
||||||
import oppen.ariane.ui.modals_menus.overflow.OverflowPopup
|
import oppen.ariane.ui.modals_menus.overflow.OverflowPopup
|
||||||
import oppen.ariane.ui.modals_menus.set_home.SetHomeDialog
|
|
||||||
import oppen.ariane.ui.settings.SettingsActivity
|
import oppen.ariane.ui.settings.SettingsActivity
|
||||||
import oppen.hideKeyboard
|
import oppen.hideKeyboard
|
||||||
import oppen.visibleRetainingSpace
|
import oppen.visibleRetainingSpace
|
||||||
|
@ -63,7 +59,15 @@ class GemActivity : AppCompatActivity() {
|
||||||
LinkPopup.show(view, uri){ menuId ->
|
LinkPopup.show(view, uri){ menuId ->
|
||||||
when (menuId) {
|
when (menuId) {
|
||||||
R.id.link_menu_load_image -> {
|
R.id.link_menu_load_image -> {
|
||||||
adapter.loadImage(position)
|
loadingView(true)
|
||||||
|
model.requestInlineImage(uri){ imageUri ->
|
||||||
|
imageUri?.let{
|
||||||
|
runOnUiThread {
|
||||||
|
loadingView(false)
|
||||||
|
adapter.loadImage(position, imageUri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
R.id.link_menu_copy -> {
|
R.id.link_menu_copy -> {
|
||||||
Intent().apply {
|
Intent().apply {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package oppen.ariane.ui
|
package oppen.ariane.ui
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import oppen.ariane.Ariane
|
import oppen.ariane.Ariane
|
||||||
import oppen.ariane.io.gemini.Datasource
|
import oppen.ariane.io.gemini.Datasource
|
||||||
|
@ -42,6 +43,15 @@ class GemViewModel: ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun requestInlineImage(uri: URI, onImageReady: (cacheUri: Uri?) -> Unit){
|
||||||
|
gemini.request(uri){ state ->
|
||||||
|
when (state) {
|
||||||
|
is GemState.ResponseImage -> onImageReady(state.cacheUri)
|
||||||
|
else -> onState(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun canGoBack(): Boolean = history.size > 1
|
fun canGoBack(): Boolean = history.size > 1
|
||||||
|
|
||||||
@ExperimentalStdlibApi
|
@ExperimentalStdlibApi
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package oppen.ariane.ui
|
package oppen.ariane.ui
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.net.Uri
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -15,8 +16,7 @@ import java.net.URI
|
||||||
class GemtextAdapter(val onLink: (adapter: GemtextAdapter, link: URI, longTap: Boolean, adapterPosition: Int, 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 inlineImages = HashMap<Int, Uri>()
|
||||||
var imageIndexes = arrayListOf<Int>()
|
|
||||||
|
|
||||||
private val typeText = 0
|
private val typeText = 0
|
||||||
private val typeH1 = 1
|
private val typeH1 = 1
|
||||||
|
@ -39,6 +39,7 @@ class GemtextAdapter(val onLink: (adapter: GemtextAdapter, link: URI, longTap: B
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(lines: List<String>){
|
fun render(lines: List<String>){
|
||||||
|
this.inlineImages.clear()
|
||||||
this.lines.clear()
|
this.lines.clear()
|
||||||
this.lines.addAll(lines)
|
this.lines.addAll(lines)
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
|
@ -114,6 +115,7 @@ class GemtextAdapter(val onLink: (adapter: GemtextAdapter, link: URI, longTap: B
|
||||||
val uri = getUri(lines[holder.adapterPosition])
|
val uri = getUri(lines[holder.adapterPosition])
|
||||||
println("User click link: $uri")
|
println("User click link: $uri")
|
||||||
onLink(this, uri, false, holder.adapterPosition, 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])
|
||||||
|
@ -122,12 +124,10 @@ class GemtextAdapter(val onLink: (adapter: GemtextAdapter, link: URI, longTap: B
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
if(imageIndexes.contains(holder.adapterPosition)){
|
if(inlineImages.containsKey(position)){
|
||||||
holder.itemView.gemtext_inline_image.visible(true)
|
holder.itemView.gemtext_inline_image.visible(true)
|
||||||
|
holder.itemView.gemtext_inline_image.setImageURI(inlineImages[position])
|
||||||
//todo - need to download the image...
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,8 +145,8 @@ class GemtextAdapter(val onLink: (adapter: GemtextAdapter, link: URI, longTap: B
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadImage(position: Int){
|
fun loadImage(position: Int, cacheUri: Uri){
|
||||||
imageIndexes.add(position)
|
inlineImages[position] = cacheUri
|
||||||
notifyItemChanged(position)
|
notifyItemChanged(position)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -16,10 +16,10 @@ object LinkPopup {
|
||||||
val inflater: MenuInflater = popup.menuInflater
|
val inflater: MenuInflater = popup.menuInflater
|
||||||
|
|
||||||
val path = uri.toString().toLowerCase()
|
val path = uri.toString().toLowerCase()
|
||||||
if(Ariane.Companion.FEATURE_INLINE_IMAGES &&
|
if(Ariane.FEATURE_INLINE_IMAGES &&
|
||||||
path.endsWith(".png") ||
|
(path.endsWith(".png") ||
|
||||||
path.endsWith(".jpg") ||
|
path.endsWith(".jpg") ||
|
||||||
path.endsWith(".jpeg")){
|
path.endsWith(".jpeg"))){
|
||||||
inflater.inflate(R.menu.image_link_menu, popup.menu)
|
inflater.inflate(R.menu.image_link_menu, popup.menu)
|
||||||
}else{
|
}else{
|
||||||
inflater.inflate(R.menu.link_menu, popup.menu)
|
inflater.inflate(R.menu.link_menu, popup.menu)
|
||||||
|
|
|
@ -51,7 +51,7 @@ object OverflowPopup {
|
||||||
* Converts the given MenuItem's title into a Spannable containing both its icon and title.
|
* Converts the given MenuItem's title into a Spannable containing both its icon and title.
|
||||||
*/
|
*/
|
||||||
private fun insertMenuItemIcon(context: Context, menuItem: MenuItem) {
|
private fun insertMenuItemIcon(context: Context, menuItem: MenuItem) {
|
||||||
var icon: Drawable = menuItem.icon
|
val icon: Drawable = menuItem.icon
|
||||||
val iconSize = context.resources.getDimensionPixelSize(R.dimen.menu_item_icon_size)
|
val iconSize = context.resources.getDimensionPixelSize(R.dimen.menu_item_icon_size)
|
||||||
icon.setBounds(0, 0, iconSize, iconSize)
|
icon.setBounds(0, 0, iconSize, iconSize)
|
||||||
icon.setTint(Color.WHITE)
|
icon.setTint(Color.WHITE)
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
android:id="@+id/gemtext_inline_image"
|
android:id="@+id/gemtext_inline_image"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="@dimen/screen_margin"
|
||||||
|
android:layout_marginRight="@dimen/screen_margin"
|
||||||
|
android:layout_marginTop="@dimen/default_margin"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
android:layout_below="@+id/gemtext_text_link"/>
|
android:layout_below="@+id/gemtext_text_link"/>
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
|
@ -3,15 +3,14 @@
|
||||||
<string name="gemini_protocol">gemini://</string>
|
<string name="gemini_protocol">gemini://</string>
|
||||||
<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">Share address</string>
|
||||||
<string name="load_image">Load image</string>
|
<string name="load_image">Display inline</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>
|
||||||
<string name="share">Share</string>
|
<string name="share">Share</string>
|
||||||
<string name="set_home">Set Home</string>
|
<string name="set_home">Set Home</string>
|
||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="home_icon_attribution">Home icon by Icongeek26 on FlatIcon.com</string>
|
|
||||||
<string name="about_body">Ariane: Gemini protocol client from Öppenlab</string>
|
<string name="about_body">Ariane: Gemini protocol client from Öppenlab</string>
|
||||||
<string name="gnu_link">GPL v3</string>
|
<string name="gnu_link">GPL v3</string>
|
||||||
<string name="copyright">Copyright © 2020 Öppenlab</string>
|
<string name="copyright">Copyright © 2020 Öppenlab</string>
|
||||||
|
|
Loading…
Reference in New Issue