Merge branch 'develop' into 'master'

Release

See merge request sschueller/peertube!49
This commit is contained in:
Stefan Schüller 2022-01-01 18:48:39 +00:00
commit e35d25a292
7 changed files with 172 additions and 62 deletions

View File

@ -175,11 +175,11 @@ public class AccountActivity extends CommonActivity {
if (response.isSuccessful()) { if (response.isSuccessful()) {
Account account = response.body(); Account account = response.body();
String owner = MetaDataHelper.getOwnerString(account.getName(), String owner = MetaDataHelper.getOwnerString(account,
account.getHost(), AccountActivity.this, true
AccountActivity.this
); );
// set view data // set view data
TextView ownerStringView = findViewById(R.id.account_owner_string); TextView ownerStringView = findViewById(R.id.account_owner_string);
ownerStringView.setText(owner); ownerStringView.setText(owner);

View File

@ -94,15 +94,15 @@ public class ChannelAdapter extends RecyclerView.Adapter<ChannelAdapter.AccountV
holder.videoMeta.setText( holder.videoMeta.setText(
MetaDataHelper.getMetaString(videoList.get(position).getCreatedAt(), MetaDataHelper.getMetaString(videoList.get(position).getCreatedAt(),
videoList.get(position).getViews(), videoList.get(position).getViews(),
context context,
false
) )
); );
// set owner // set owner
holder.videoOwner.setText( holder.videoOwner.setText(
MetaDataHelper.getOwnerString(videoList.get(position).getAccount().getName(), MetaDataHelper.getOwnerString(videoList.get(position).getAccount(),
videoList.get(position).getAccount().getHost(), context, true
context
) )
); );

View File

@ -16,7 +16,9 @@
*/ */
package net.schueller.peertube.adapter package net.schueller.peertube.adapter
import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.util.Log import android.util.Log
import android.view.MenuItem import android.view.MenuItem
@ -39,10 +41,14 @@ import net.schueller.peertube.helper.MetaDataHelper.getDuration
import net.schueller.peertube.helper.MetaDataHelper.getMetaString import net.schueller.peertube.helper.MetaDataHelper.getMetaString
import net.schueller.peertube.helper.MetaDataHelper.getOwnerString import net.schueller.peertube.helper.MetaDataHelper.getOwnerString
import com.mikepenz.iconics.Iconics.Builder import com.mikepenz.iconics.Iconics.Builder
import net.schueller.peertube.R
import net.schueller.peertube.R.id import net.schueller.peertube.R.id
import net.schueller.peertube.R.menu import net.schueller.peertube.R.menu
import net.schueller.peertube.databinding.* import net.schueller.peertube.databinding.*
import net.schueller.peertube.fragment.VideoMetaDataFragment import net.schueller.peertube.fragment.VideoMetaDataFragment
import net.schueller.peertube.helper.MetaDataHelper.getCreatorAvatar
import net.schueller.peertube.helper.MetaDataHelper.getCreatorString
import net.schueller.peertube.helper.MetaDataHelper.getTagsString
import net.schueller.peertube.intents.Intents import net.schueller.peertube.intents.Intents
import net.schueller.peertube.model.* import net.schueller.peertube.model.*
import net.schueller.peertube.model.ui.VideoMetaViewItem import net.schueller.peertube.model.ui.VideoMetaViewItem
@ -55,7 +61,7 @@ import okhttp3.ResponseBody
import retrofit2.Call import retrofit2.Call
import retrofit2.Callback import retrofit2.Callback
import retrofit2.Response import retrofit2.Response
import net.schueller.peertube.R import net.schueller.peertube.helper.MetaDataHelper.isChannel
import net.schueller.peertube.network.GetUserService import net.schueller.peertube.network.GetUserService
@ -190,10 +196,26 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
binding.videoDownloadWrapper.visibility = GONE binding.videoDownloadWrapper.visibility = GONE
} }
val account = video.account // created at / views
binding.videoMeta.text = getMetaString(
video.createdAt,
video.views,
context,
true
)
// owner / creator
val displayNameAndHost = getOwnerString(video.account, context)
if (isChannel(video)) {
binding.videoBy.text = context.resources.getString(string.video_by_line, displayNameAndHost)
} else {
binding.videoBy.visibility = GONE
}
binding.videoOwner.text = getCreatorString(video, context)
// owner / creator Avatar // owner / creator Avatar
val avatar = account.avatar val avatar = getCreatorAvatar(video, context)
if (avatar != null) { if (avatar != null) {
val baseUrl = APIUrlHelper.getUrl(context) val baseUrl = APIUrlHelper.getUrl(context)
val avatarPath = avatar.path val avatarPath = avatar.path
@ -201,22 +223,25 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
.load(baseUrl + avatarPath) .load(baseUrl + avatarPath)
.into(binding.avatar) .into(binding.avatar)
} }
// created at / views
binding.videoMeta.text = getMetaString(
video.createdAt,
video.views,
context!!
)
// owner / creator
binding.videoOwner.text = getOwnerString(
video.account.name,
video.account.host,
context
)
// videoOwnerSubscribers // videoOwnerSubscribers
binding.videoOwnerSubscribers.text = video.account.followersCount.toString() binding.videoOwnerSubscribers.text = context.resources.getQuantityString(R.plurals.video_channel_subscribers, video.channel.followersCount, video.channel.followersCount)
// video owner click
binding.videoCreatorInfo.setOnClickListener {
val intent = Intent(context, AccountActivity::class.java)
intent.putExtra(VideoListActivity.EXTRA_ACCOUNTDISPLAYNAME, displayNameAndHost)
context.startActivity(intent)
}
// avatar click
binding.avatar.setOnClickListener {
val intent = Intent(context, AccountActivity::class.java)
intent.putExtra(Companion.EXTRA_ACCOUNTDISPLAYNAME, displayNameAndHost)
context.startActivity(intent)
}
// get subscription status // get subscription status
@ -231,7 +256,7 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
// {"video.channel.name + "@" + video.channel.host":true} // {"video.channel.name + "@" + video.channel.host":true}
if (response.body()?.get(video.channel.name + "@" + video.channel.host)!!.asBoolean) { if (response.body()?.get(video.channel.name + "@" + video.channel.host)!!.asBoolean) {
binding.videoOwnerSubscribeButton.setText(string.unsubscribe) binding.videoOwnerSubscribeButton.setText(string.unsubscribe)
isSubscribed = true; isSubscribed = true
} else { } else {
binding.videoOwnerSubscribeButton.setText(string.subscribe) binding.videoOwnerSubscribeButton.setText(string.subscribe)
} }
@ -244,6 +269,7 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
} }
// TODO: update subscriber count
binding.videoOwnerSubscribeButton.setOnClickListener { binding.videoOwnerSubscribeButton.setOnClickListener {
if (Session.getInstance().isLoggedIn) { if (Session.getInstance().isLoggedIn) {
if (!isSubscribed) { if (!isSubscribed) {
@ -265,6 +291,11 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
} }
}) })
} else { } else {
AlertDialog.Builder(context)
.setTitle(context.getString(string.video_sub_del_alert_title))
.setMessage(context.getString(string.video_sub_del_alert_msg))
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
// Yes
val payload = video.channel.name + "@" + video.channel.host val payload = video.channel.name + "@" + video.channel.host
val call = userService.unsubscribe(payload) val call = userService.unsubscribe(payload)
call.enqueue(object : Callback<ResponseBody?> { call.enqueue(object : Callback<ResponseBody?> {
@ -282,6 +313,12 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
} }
}) })
} }
.setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int ->
// No
}
.setIcon(android.R.drawable.ic_dialog_alert)
.show()
}
} else { } else {
Toast.makeText( Toast.makeText(
context, context,
@ -337,7 +374,7 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
.into(binding.thumb) .into(binding.thumb)
// Avatar // Avatar
val avatar: Avatar? = video.account.avatar val avatar = getCreatorAvatar(video, context)
if (avatar != null) { if (avatar != null) {
val avatarPath = avatar.path val avatarPath = avatar.path
Picasso.get() Picasso.get()
@ -364,12 +401,8 @@ sealed class MultiViewRecyclerViewHolder(binding: ViewBinding) : RecyclerView.Vi
) )
// set owner // set owner
val displayNameAndHost = getOwnerString( val displayNameAndHost = getOwnerString(video.account, context, true)
video.account.name, binding.videoOwner.text = getCreatorString(video, context, true)
video.account.host,
context
)
binding.videoOwner.text = displayNameAndHost
// video owner click // video owner click
binding.videoOwner.setOnClickListener { binding.videoOwner.setOnClickListener {

View File

@ -18,31 +18,91 @@ package net.schueller.peertube.helper
import android.content.Context import android.content.Context
import android.text.format.DateUtils import android.text.format.DateUtils
import net.schueller.peertube.R
import net.schueller.peertube.R.string import net.schueller.peertube.R.string
import net.schueller.peertube.model.Account
import net.schueller.peertube.model.Avatar
import net.schueller.peertube.model.Video
import org.ocpsoft.prettytime.PrettyTime import org.ocpsoft.prettytime.PrettyTime
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import kotlin.math.absoluteValue
object MetaDataHelper { object MetaDataHelper {
@JvmStatic @JvmStatic
fun getMetaString(getCreatedAt: Date, viewCount: Int, context: Context): String { fun getMetaString(getCreatedAt: Date, viewCount: Int, context: Context, reversed: Boolean = false): String {
// Compatible with SDK 21+ // Compatible with SDK 21+
val currentLanguage = Locale.getDefault().displayLanguage val currentLanguage = Locale.getDefault().displayLanguage
val p = PrettyTime(currentLanguage) val p = PrettyTime(currentLanguage)
val relativeTime = p.format(Date(getCreatedAt.time)) val relativeTime = p.format(Date(getCreatedAt.time))
return relativeTime + return if (reversed) {
viewCount.toString() +
context.resources.getString(string.meta_data_views) +
context.resources.getString(string.meta_data_seperator) +
relativeTime
} else {
relativeTime +
context.resources.getString(string.meta_data_seperator) + context.resources.getString(string.meta_data_seperator) +
viewCount + context.resources.getString(string.meta_data_views) viewCount + context.resources.getString(string.meta_data_views)
} }
}
fun getTagsString(video: Video): String {
return if (video.tags.isNotEmpty()) {
" #" + video.tags.joinToString(" #", "", "", 3, "")
} else {
" "
}
}
@JvmStatic @JvmStatic
fun getOwnerString(accountName: String, serverHost: String, context: Context): String { fun getCreatorString(video: Video, context: Context, fqdn: Boolean = false): String {
return accountName + return if (isChannel(video)) {
context.resources.getString(string.meta_data_owner_seperator) + if (!fqdn) {
serverHost video.channel.displayName
} else {
getConcatFqdnString(video.channel.name, video.channel.host, context)
} }
} else {
getOwnerString(video.account, context, fqdn)
}
}
@JvmStatic
fun getOwnerString(account: Account, context: Context, fqdn: Boolean = true): String {
return if (!fqdn) {
account.name
} else {
getConcatFqdnString(account.name, account.host, context)
}
}
private fun getConcatFqdnString(user: String, host: String, context: Context): String {
return context.resources.getString(string.video_owner_fqdn_line, user, host)
}
@JvmStatic
fun getCreatorAvatar(video: Video, context: Context): Avatar? {
return if (isChannel(video)) {
if (video.channel.avatar == null) {
video.account.avatar
} else {
video.channel.avatar
}
} else {
video.account.avatar
}
}
@JvmStatic
fun isChannel(video: Video): Boolean {
// c285b523-d688-43c5-a9ad-f745ff09bbd1
return !video.channel.name.matches("[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}".toRegex())
}
@JvmStatic @JvmStatic
fun getDuration(duration: Long?): String { fun getDuration(duration: Long?): String {

View File

@ -13,6 +13,7 @@
<!-- Video Title Block --> <!-- Video Title Block -->
<RelativeLayout <RelativeLayout
android:background="?android:selectableItemBackground"
android:id="@+id/video_title_block" android:id="@+id/video_title_block"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -331,20 +332,20 @@
<de.hdodenhof.circleimageview.CircleImageView <de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/avatar" android:id="@+id/avatar"
android:layout_width="72dp" android:layout_width="48dp"
android:layout_height="72dp" android:layout_height="48dp"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:contentDescription="@string/video_row_account_avatar" android:contentDescription="@string/video_row_account_avatar"
android:paddingStart="12dp" android:paddingStart="6dp"
android:paddingTop="12dp" android:paddingEnd="6dp" />
android:paddingEnd="12dp" />
<LinearLayout <LinearLayout
android:id="@+id/video_creator_info"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginStart="12dp" android:layout_marginStart="6dp"
android:layout_toEndOf="@+id/avatar" android:layout_toEndOf="@+id/avatar"
android:orientation="vertical"> android:orientation="vertical">
@ -354,6 +355,13 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Subhead" /> android:textAppearance="@style/Base.TextAppearance.AppCompat.Subhead" />
<TextView
android:id="@+id/videoBy"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:textAppearance="@style/Base.TextAppearance.AppCompat.Caption" />
<TextView <TextView
android:id="@+id/videoOwnerSubscribers" android:id="@+id/videoOwnerSubscribers"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -367,11 +375,13 @@
android:id="@+id/videoOwnerSubscribeButton" android:id="@+id/videoOwnerSubscribeButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentRight="true" android:layout_alignParentEnd="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginTop="0dp" android:layout_marginTop="0dp"
android:layout_marginEnd="0dp" android:layout_marginEnd="0dp"
android:gravity="end" android:gravity="end"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:text="" android:text=""
android:textAppearance="@style/Base.TextAppearance.AppCompat.Button" /> android:textAppearance="@style/Base.TextAppearance.AppCompat.Button" />

View File

@ -58,7 +58,6 @@
<string name="video_download_icon" translatable="false">{faw-download}</string> <string name="video_download_icon" translatable="false">{faw-download}</string>
<string name="video_save_icon" translatable="false">{faw-save}</string> <string name="video_save_icon" translatable="false">{faw-save}</string>
<string name="meta_data_owner_seperator" translatable="false">\@</string>
<string name="meta_data_seperator" translatable="false">\u0020-\u0020</string> <string name="meta_data_seperator" translatable="false">\u0020-\u0020</string>
<string name="title_activity_video_play" translatable="false">VideoPlayActivity</string> <string name="title_activity_video_play" translatable="false">VideoPlayActivity</string>

View File

@ -376,4 +376,12 @@
<string name="subscribe">Subscribe</string> <string name="subscribe">Subscribe</string>
<string name="unsubscribe">Unsubscribe</string> <string name="unsubscribe">Unsubscribe</string>
<string name="video_comments_title">Comments</string> <string name="video_comments_title">Comments</string>
<plurals name="video_channel_subscribers">
<item quantity="one">%1$d subscriber</item>
<item quantity="other">%1$d subscribers</item>
</plurals>
<string name="video_by_line">By %1$s</string>
<string name="video_owner_fqdn_line">%1$s@%2$s</string>
<string name="video_sub_del_alert_title">Unsubscribe</string>
<string name="video_sub_del_alert_msg">Are you sure you would like to unsubscribe?</string>
</resources> </resources>