Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/assets/changelog-alpha.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/Alpha 359 (2025-04-20)
Added support for emotes in comment flairs (thanks to bharatknv)
Ability to follow/unfollow users (thanks to folkemat)
Added "Mark as Read/Unread" fling action, and optional context menu item (thanks to JoshAusHessen and codeofdusk)

/Alpha 358 (2025-03-12)
Expand Down
1 change: 1 addition & 0 deletions src/main/assets/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
114/1.25
Added video playback speed control (thanks to folkemat)
Ability to follow/unfollow users (thanks to folkemat)
Added support for emotes in comment flairs (thanks to bharatknv)
Added "Mark as Read/Unread" fling action, and optional context menu item (thanks to JoshAusHessen and codeofdusk)
Added preference to prevent posts being marked as read when clicked (thanks to Daniel Ho)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ package org.quantumbadger.redreader.fragments

import android.content.Intent
import android.graphics.BitmapFactory
import android.net.Uri
import android.util.Log
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.ScrollView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.net.toUri
import com.google.android.material.card.MaterialCardView
import com.google.android.material.chip.Chip
import com.google.android.material.dialog.MaterialAlertDialogBuilder
Expand Down Expand Up @@ -55,7 +56,11 @@ import org.quantumbadger.redreader.reddit.APIResponseHandler.ActionResponseHandl
import org.quantumbadger.redreader.reddit.APIResponseHandler.UserResponseHandler
import org.quantumbadger.redreader.reddit.RedditAPI
import org.quantumbadger.redreader.reddit.api.RedditOAuth.completeLogin
import org.quantumbadger.redreader.reddit.api.RedditSubredditSubscriptionManager
import org.quantumbadger.redreader.reddit.api.SubredditSubscriptionState
import org.quantumbadger.redreader.reddit.things.InvalidSubredditNameException
import org.quantumbadger.redreader.reddit.things.RedditUser
import org.quantumbadger.redreader.reddit.things.SubredditCanonicalId
import org.quantumbadger.redreader.reddit.url.UserPostListingURL
import org.quantumbadger.redreader.views.LoadingSpinnerView
import org.quantumbadger.redreader.views.liststatus.ErrorView
Expand Down Expand Up @@ -94,6 +99,9 @@ object UserProfileDialog {
val chipMoreInfo = dialog.findViewById<Chip>(R.id.user_profile_chip_more_info)!!
val chipBlock = dialog.findViewById<Chip>(R.id.user_profile_chip_block)!!
val chipUnblock = dialog.findViewById<Chip>(R.id.user_profile_chip_unblock)!!
val chipFollow = dialog.findViewById<Chip>(R.id.user_profile_chip_follow)!!
val chipFollowed = dialog.findViewById<Chip>(R.id.user_profile_chip_followed)!!
val chipUnfollow = dialog.findViewById<Chip>(R.id.user_profile_chip_unfollow)!!

val cm = CacheManager.getInstance(activity)
val accountManager = RedditAccountManager.getInstance(activity)
Expand Down Expand Up @@ -132,18 +140,26 @@ object UserProfileDialog {
accountManager.getDefaultAccount().canonicalUsername
)) {
chipYou.visibility = View.GONE
}else{
chipBlock.visibility = View.GONE //you should not block yourself
} else{
// You should not block yourself
chipBlock.visibility = View.GONE
chipFollow.visibility = View.GONE
}

if (user.is_suspended != true) {
chipSuspended.visibility = View.GONE
}

if (accountManager.getDefaultAccount().isAnonymous()) {
chipBlock.visibility = View.GONE
chipUnblock.visibility = View.GONE
chipBlocked.visibility = View.GONE
if (accountManager.getDefaultAccount().isAnonymous) {
listOf(
chipBlock,
chipUnblock,
chipBlocked,
chipFollow,
chipUnfollow,
chipFollowed
).forEach { it.visibility = View.GONE }

} else { //show block actions only if user is logged in
if (user.is_blocked != true) {
chipBlocked.visibility = View.GONE
Expand All @@ -152,6 +168,19 @@ object UserProfileDialog {
chipBlock.visibility = View.GONE
chipUnblock.visibility = View.VISIBLE
}

val userSubredditCanonicalIdA = SubredditCanonicalId("/user/$username")
val userSubredditCanonicalIdB = SubredditCanonicalId("u_$username")
val subMan = getSubMan(activity)
if (subMan.getSubscriptionState(userSubredditCanonicalIdA) == SubredditSubscriptionState.NOT_SUBSCRIBED &&
subMan.getSubscriptionState(userSubredditCanonicalIdB) == SubredditSubscriptionState.NOT_SUBSCRIBED) {
chipFollowed.visibility = View.GONE
chipFollow.visibility = View.VISIBLE
chipUnfollow.visibility = View.GONE
} else {
chipFollow.visibility = View.GONE
chipUnfollow.visibility = View.VISIBLE
}
}

if (user.is_friend != true) {
Expand Down Expand Up @@ -258,6 +287,12 @@ object UserProfileDialog {
chipUnblock.isEnabled = false // grey out
unblockUser(activity, username, chipBlock, chipBlocked, chipUnblock)
}
chipFollow.setOnClickListener {
subscribeToUser(activity, username)
}
chipUnfollow.setOnClickListener {
unsubscribeToUser(activity, username)
}
}
}

Expand All @@ -282,6 +317,66 @@ object UserProfileDialog {
)
}

private fun subscribeToUser(activity: AppCompatActivity, username: String) {
try {
val usernameToSubreddit = "u_$username"
val userSubredditCanonicalId = SubredditCanonicalId(usernameToSubreddit)

val subMan = getSubMan(activity)
if ((subMan.getSubscriptionState(userSubredditCanonicalId)
== SubredditSubscriptionState.NOT_SUBSCRIBED)
) {
subMan.subscribe(userSubredditCanonicalId, activity)
Toast.makeText(
activity,
R.string.userprofile_toast_follow_loading,
Toast.LENGTH_SHORT
).show()
} else {
Toast.makeText(
activity,
R.string.userprofile_toast_followed,
Toast.LENGTH_SHORT
).show()
}
} catch (e: InvalidSubredditNameException) {
throw RuntimeException(e)
}
}

private fun unsubscribeToUser(activity: AppCompatActivity, username: String) {
try {
val userSubredditCanonicalIdA = SubredditCanonicalId("/user/$username")
val userSubredditCanonicalIdB = SubredditCanonicalId("u_$username")

val subMan = getSubMan(activity)

fun unsubscribeIfSubscribed(canonicalId: SubredditCanonicalId): Boolean {
return if (subMan.getSubscriptionState(canonicalId) == SubredditSubscriptionState.SUBSCRIBED) {
subMan.unsubscribe(canonicalId, activity)
Toast.makeText(activity, R.string.userprofile_toast_unfollow_loading, Toast.LENGTH_SHORT).show()
true
} else {
false
}
}

if (!unsubscribeIfSubscribed(userSubredditCanonicalIdA) && !unsubscribeIfSubscribed(userSubredditCanonicalIdB)) {
Toast.makeText(activity, R.string.userprofile_toast_not_following, Toast.LENGTH_SHORT).show()
}
} catch (e: InvalidSubredditNameException) {
throw RuntimeException(e)
}
}

private fun getSubMan(activity: AppCompatActivity): RedditSubredditSubscriptionManager {
val subMan = RedditSubredditSubscriptionManager.getSingleton(
activity,
RedditAccountManager.getInstance(activity).defaultAccount
)
return subMan
}

private fun unblockUser(activity: AppCompatActivity, username: String, chipBlock: Chip, chipBlocked: Chip, chipUnblock: Chip) {
val cm = CacheManager.getInstance(activity)
val currentUser = RedditAccountManager.getInstance(activity).defaultAccount
Expand Down Expand Up @@ -416,8 +511,10 @@ object UserProfileDialog {
) { resultCode: Int, data: Intent? ->
if (data != null) {
if (resultCode == 123 && data.hasExtra("url")) {
val uri = Uri.parse(data.getStringExtra("url"))
completeLogin(activity, uri, RunnableOnce.DO_NOTHING)
val uri = data.getStringExtra("url")?.toUri()
if (uri != null) {
completeLogin(activity, uri, RunnableOnce.DO_NOTHING)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ protected void prepare(
false));
}

if (user.is_followed != null) {
items.addView(propView(
context,
R.string.userprofile_tag_followed,
user.is_followed ? R.string.general_true : R.string.general_false,
false));
}

if (user.is_employee != null) {
items.addView(propView(
context,
Expand All @@ -131,6 +139,14 @@ protected void prepare(
false));
}

if (user.is_followed != null) {
items.addView(propView(
context,
R.string.userprofile_tag_followed,
user.is_followed ? R.string.general_true : R.string.general_false,
false));
}

if (user.icon_img != null) {
items.addView(propView(
context,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class RedditUser implements Parcelable, JsonObject.JsonDeserializable {
@Nullable public Boolean is_suspended;
@Nullable public Boolean over_18;
@Nullable public Boolean is_blocked;
@Nullable public Boolean is_followed;

@Nullable public String id;
@NonNull public String name;
Expand Down Expand Up @@ -87,6 +88,7 @@ private RedditUser(final Parcel in) {
is_mod = in.readInt() == 1;
over_18 = in.readInt() == 1;
is_blocked = in.readInt() == 1;
is_followed = in.readInt() == 1;

id = in.readString();
name = in.readString();
Expand Down Expand Up @@ -121,6 +123,7 @@ public void writeToParcel(final Parcel parcel, final int flags) {
parcel.writeInt(is_mod ? 1 : 0);
parcel.writeInt(over_18 ? 1 : 0);
parcel.writeInt(is_blocked ? 1 : 0);
parcel.writeInt(is_followed ? 1 : 0);

parcel.writeString(id);
parcel.writeString(name);
Expand Down
30 changes: 30 additions & 0 deletions src/main/res/layout/user_profile_dialog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,16 @@
android:checkable="false"
app:chipMinTouchTargetSize="0dp"/>

<com.google.android.material.chip.Chip
android:id="@+id/user_profile_chip_followed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/userprofile_tag_followed"
style="@style/Widget.Material3.Chip.Assist"
android:clickable="false"
android:checkable="false"
app:chipMinTouchTargetSize="0dp"/>

</com.google.android.material.chip.ChipGroup>

<com.google.android.material.card.MaterialCardView
Expand Down Expand Up @@ -349,6 +359,26 @@
style="@style/Widget.Material3.Chip.Assist.Elevated"
android:checkable="false"/>

<com.google.android.material.chip.Chip
android:id="@+id/user_profile_chip_follow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipIcon="?rrIconPerson"
app:chipIconSize="16sp"
android:text="@string/userprofile_button_follow"
style="@style/Widget.Material3.Chip.Assist.Elevated"
android:checkable="false"/>

<com.google.android.material.chip.Chip
android:id="@+id/user_profile_chip_unfollow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipIcon="?rrIconCross"
app:chipIconSize="16sp"
android:text="@string/userprofile_button_unfollow"
style="@style/Widget.Material3.Chip.Assist.Elevated"
android:checkable="false"/>

</com.google.android.material.chip.ChipGroup>

</androidx.appcompat.widget.LinearLayoutCompat>
Expand Down
8 changes: 8 additions & 0 deletions src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1914,4 +1914,12 @@
<string name="pref_behaviour_mark_posts_as_read_key" translatable="false">pref_behaviour_mark_posts_as_read</string>
<string name="pref_behaviour_mark_posts_as_read_title">Mark posts as read</string>

<string name="userprofile_button_follow" translatable="true">Follow</string>
<string name="userprofile_toast_follow_loading" translatable="true">Following…</string>
<string name="userprofile_tag_followed" translatable="true">Followed</string>
<string name="userprofile_toast_followed" translatable="true">You are already following this user!</string>
<string name="userprofile_button_unfollow" translatable="true">Unfollow</string>
<string name="userprofile_toast_unfollow_loading" translatable="true">Unfollowing…</string>
<string name="userprofile_toast_not_following" translatable="true">You are not following this user!</string>

</resources>
Loading