mirror of
https://codeberg.org/Bazsalanszky/Infinity-For-Lemmy.git
synced 2024-11-10 04:37:25 +01:00
Linkify community and user names
This commit makes user and community names clickable in post/comments. Closes #71?
This commit is contained in:
parent
60f07f7707
commit
9872e6e806
@ -1,5 +1,6 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
|
||||
android {
|
||||
@ -34,6 +35,11 @@ android {
|
||||
versionNameSuffix ' (DEBUG)'
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_11
|
||||
targetCompatibility JavaVersion.VERSION_11
|
||||
|
@ -690,9 +690,8 @@ public class ViewSubredditDetailActivity extends BaseActivity implements SortTyp
|
||||
qualifiedName = LemmyUtils.actorID2FullName(communityData.getActorId());
|
||||
if (communityName == null) {
|
||||
communityName = communityData.getTitle();
|
||||
|
||||
setupVisibleElements();
|
||||
}
|
||||
setupVisibleElements();
|
||||
communityId = communityData.getId();
|
||||
setupSubscribeChip();
|
||||
|
||||
|
@ -40,6 +40,7 @@ import eu.toldi.infinityforlemmy.markdown.MarkdownUtils;
|
||||
import eu.toldi.infinityforlemmy.subreddit.FetchSubredditData;
|
||||
import eu.toldi.infinityforlemmy.subreddit.SubredditData;
|
||||
import eu.toldi.infinityforlemmy.subreddit.SubredditViewModel;
|
||||
import eu.toldi.infinityforlemmy.utils.LemmyUtils;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonConfiguration;
|
||||
@ -97,7 +98,7 @@ public class SidebarFragment extends Fragment {
|
||||
mAccessToken = getArguments().getString(EXTRA_ACCESS_TOKEN);
|
||||
subredditName = getArguments().getString(EXTRA_SUBREDDIT_NAME);
|
||||
communityQualifiedName = getArguments().getString(EXTRA_COMMUNITY_QUALIFIED_NAME);
|
||||
if (subredditName == null) {
|
||||
if (communityQualifiedName == null) {
|
||||
Toast.makeText(activity, R.string.error_getting_community_name, Toast.LENGTH_SHORT).show();
|
||||
return rootView;
|
||||
}
|
||||
@ -166,7 +167,7 @@ public class SidebarFragment extends Fragment {
|
||||
});
|
||||
|
||||
mSubredditViewModel = new ViewModelProvider(activity,
|
||||
new SubredditViewModel.Factory(activity.getApplication(), mRedditDataRoomDatabase, communityQualifiedName))
|
||||
new SubredditViewModel.Factory(activity.getApplication(), mRedditDataRoomDatabase, LemmyUtils.qualifiedCommunityName2ActorId(communityQualifiedName)))
|
||||
.get(SubredditViewModel.class);
|
||||
mSubredditViewModel.getSubredditLiveData().observe(getViewLifecycleOwner(), subredditData -> {
|
||||
if (subredditData != null) {
|
||||
|
@ -52,6 +52,7 @@ public class MarkdownUtils {
|
||||
.usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS))
|
||||
.usePlugin(TableEntryPlugin.create(context))
|
||||
.usePlugin(ClickableGlideImagesPlugin.create(context))
|
||||
.usePlugin(new MarkwonLemmyLinkPlugin())
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -71,6 +72,7 @@ public class MarkdownUtils {
|
||||
.usePlugin(LinkifyPlugin.create(Linkify.WEB_URLS))
|
||||
.usePlugin(TableEntryPlugin.create(context))
|
||||
.usePlugin(GlideImagesPlugin.create(context))
|
||||
.usePlugin(new MarkwonLemmyLinkPlugin())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,88 @@
|
||||
package eu.toldi.infinityforlemmy.markdown
|
||||
|
||||
|
||||
import android.text.Spannable
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.style.URLSpan
|
||||
import android.text.util.Linkify
|
||||
import eu.toldi.infinityforlemmy.utils.LemmyUtils
|
||||
import io.noties.markwon.*
|
||||
import io.noties.markwon.core.CorePlugin
|
||||
import io.noties.markwon.core.CoreProps
|
||||
import org.commonmark.node.Link
|
||||
import java.util.regex.Pattern
|
||||
|
||||
// Source : https://github.com/dessalines/jerboa/blob/main/app/src/main/java/com/jerboa/util/markwon/MarkwonLemmyLinkPlugin.kt
|
||||
class MarkwonLemmyLinkPlugin : AbstractMarkwonPlugin() {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* pattern that matches all valid communities; intended to be loose
|
||||
*/
|
||||
const val communityPatternFragment: String = """[a-zA-Z0-9_]{3,}"""
|
||||
|
||||
/**
|
||||
* pattern to match all valid instances
|
||||
*/
|
||||
const val instancePatternFragment: String =
|
||||
"""([a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]\.)+[a-zA-Z]{2,}"""
|
||||
|
||||
/**
|
||||
* pattern to match all valid usernames
|
||||
*/
|
||||
const val userPatternFragment: String = """[a-zA-Z0-9_]{3,}"""
|
||||
|
||||
/**
|
||||
* Pattern to match lemmy's unique community pattern, e.g. !commmunity[@instance]
|
||||
*/
|
||||
val lemmyCommunityPattern: Pattern =
|
||||
Pattern.compile("(?<!\\S)!($communityPatternFragment)(?:@($instancePatternFragment))?\\b")
|
||||
|
||||
/**
|
||||
* Pattern to match lemmy's unique user pattern, e.g. @user[@instance]
|
||||
*/
|
||||
val lemmyUserPattern: Pattern =
|
||||
Pattern.compile("(?<!\\S)@($userPatternFragment)(?:@($instancePatternFragment))?\\b")
|
||||
|
||||
}
|
||||
override fun configure(registry: MarkwonPlugin.Registry) {
|
||||
registry.require(CorePlugin::class.java) { it.addOnTextAddedListener(LemmyTextAddedListener()) }
|
||||
}
|
||||
|
||||
private class LemmyTextAddedListener : CorePlugin.OnTextAddedListener {
|
||||
override fun onTextAdded(visitor: MarkwonVisitor, text: String, start: Int) {
|
||||
// we will be using the link that is used by markdown (instead of directly applying URLSpan)
|
||||
val spanFactory = visitor.configuration().spansFactory().get(
|
||||
Link::class.java,
|
||||
) ?: return
|
||||
|
||||
// don't re-use builder (thread safety achieved for
|
||||
// render calls from different threads and ... better performance)
|
||||
val builder = SpannableStringBuilder(text)
|
||||
if (addLinks(builder)) {
|
||||
// target URL span specifically
|
||||
val spans = builder.getSpans(0, builder.length, URLSpan::class.java)
|
||||
if (!spans.isNullOrEmpty()) {
|
||||
val renderProps = visitor.renderProps()
|
||||
val spannableBuilder = visitor.builder()
|
||||
for (span in spans) {
|
||||
CoreProps.LINK_DESTINATION[renderProps] = if (span.url.startsWith("!")) { LemmyUtils.qualifiedCommunityName2ActorId(span.url.drop(1)) } else { LemmyUtils.qualifiedUserName2ActorId(span.url.drop(1)) }
|
||||
SpannableBuilder.setSpans(
|
||||
spannableBuilder,
|
||||
spanFactory.getSpans(visitor.configuration(), renderProps),
|
||||
start + builder.getSpanStart(span),
|
||||
start + builder.getSpanEnd(span),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun addLinks(text: Spannable): Boolean {
|
||||
val communityLinkAdded = Linkify.addLinks(text, lemmyCommunityPattern, null)
|
||||
val userLinkAdded = Linkify.addLinks(text, lemmyUserPattern, null)
|
||||
|
||||
return communityLinkAdded || userLinkAdded
|
||||
}
|
||||
}
|
||||
}
|
@ -1352,4 +1352,6 @@
|
||||
<string name="instance_cannot_be_empty">The instance field cannot be left empty.</string>
|
||||
<string name="username_cannot_be_empty">The username field cannot be left empty.</string>
|
||||
<string name="password_cannot_be_empty">The password field cannot be left empty.</string>
|
||||
<!-- TODO: Remove or change this placeholder text -->
|
||||
<string name="hello_blank_fragment">Hello blank fragment</string>
|
||||
</resources>
|
||||
|
@ -9,6 +9,7 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.20'
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
Loading…
Reference in New Issue
Block a user