Merge pull request #596 from nitehu/feature/share-on-server

Added option whether to create a share on the server when sharing songs
This commit is contained in:
tzugen 2021-10-13 15:05:16 +02:00 committed by GitHub
commit 910a05d49d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 191 additions and 59 deletions

View File

@ -10,6 +10,7 @@ import java.util.List;
public class ShareDetails
{
public String Description;
public boolean ShareOnServer;
public long Expiration;
public List<MusicDirectory.Entry> Entries;
}

View File

@ -33,6 +33,7 @@ import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import android.widget.ViewFlipper
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import com.mobeta.android.dslv.DragSortListView
@ -153,7 +154,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
return inflater.inflate(R.layout.current_playing, container, false)
}
fun findViews(view: View) {
private fun findViews(view: View) {
playlistFlipper = view.findViewById(R.id.current_playing_playlist_flipper)
emptyTextView = view.findViewById(R.id.playlist_empty)
songTitleTextView = view.findViewById(R.id.current_playing_song)
@ -209,7 +210,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
val nextButton: AutoRepeatButton = view.findViewById(R.id.button_next)
val shuffleButton = view.findViewById<View>(R.id.button_shuffle)
val ratingLinearLayout = view.findViewById<LinearLayout>(R.id.song_rating)
if (!useFiveStarRating) ratingLinearLayout.visibility = View.GONE
if (!useFiveStarRating) ratingLinearLayout.isVisible = false
hollowStar = Util.getDrawableFromAttribute(view.context, R.attr.star_hollow)
fullStar = Util.getDrawableFromAttribute(context, R.attr.star_full)
@ -375,7 +376,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
mediaPlayerController.isShufflePlayEnabled = true
}
visualizerViewLayout.visibility = View.GONE
visualizerViewLayout.isVisible = false
VisualizerController.get().observe(
requireActivity(),
{ visualizerController ->
@ -389,11 +390,9 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
LinearLayout.LayoutParams.MATCH_PARENT
)
)
if (!visualizerView.isActive) {
visualizerViewLayout.visibility = View.GONE
} else {
visualizerViewLayout.visibility = View.VISIBLE
}
visualizerViewLayout.isVisible = visualizerView.isActive
visualizerView.setOnTouchListener { _, _ ->
visualizerView.isActive = !visualizerView.isActive
mediaPlayerController.showVisualization = visualizerView.isActive
@ -402,7 +401,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
isVisualizerAvailable = true
} else {
Timber.d("VisualizerController Observer.onChanged has no controller")
visualizerViewLayout.visibility = View.GONE
visualizerViewLayout.isVisible = false
isVisualizerAvailable = false
}
}
@ -497,6 +496,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
val equalizerMenuItem = menu.findItem(R.id.menu_item_equalizer)
val visualizerMenuItem = menu.findItem(R.id.menu_item_visualizer)
val shareMenuItem = menu.findItem(R.id.menu_item_share)
val shareSongMenuItem = menu.findItem(R.id.menu_item_share_song)
starMenuItem = menu.findItem(R.id.menu_item_star)
val bookmarkMenuItem = menu.findItem(R.id.menu_item_bookmark_set)
val bookmarkRemoveMenuItem = menu.findItem(R.id.menu_item_bookmark_delete)
@ -523,20 +523,27 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
}
val mediaPlayerController = mediaPlayerController
val downloadFile = mediaPlayerController.currentPlaying
if (downloadFile != null) {
currentSong = downloadFile.song
}
if (useFiveStarRating) starMenuItem.isVisible = false
if (currentSong != null) {
starMenuItem.icon = if (currentSong!!.starred) fullStar else hollowStar
shareSongMenuItem.isVisible = true
} else {
starMenuItem.icon = hollowStar
shareSongMenuItem.isVisible = false
}
if (mediaPlayerController.keepScreenOn) {
screenOption?.setTitle(R.string.download_menu_screen_off)
} else {
screenOption?.setTitle(R.string.download_menu_screen_on)
}
if (jukeboxOption != null) {
jukeboxOption.isEnabled = jukeboxAvailable
jukeboxOption.isVisible = jukeboxAvailable
@ -598,9 +605,8 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
when (menuItemId) {
R.id.menu_show_artist -> {
if (entry == null) {
return false
}
if (entry == null) return false
if (Settings.shouldUseId3Tags) {
bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.artistId)
@ -613,9 +619,8 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
return true
}
R.id.menu_show_album -> {
if (entry == null) {
return false
}
if (entry == null) return false
val albumId = if (Settings.shouldUseId3Tags) entry.albumId else entry.parent
bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, albumId)
@ -627,9 +632,8 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
return true
}
R.id.menu_lyrics -> {
if (entry == null) {
return false
}
if (entry == null) return false
bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ARTIST, entry.artist)
bundle.putString(Constants.INTENT_EXTRA_NAME_TITLE, entry.title)
@ -664,11 +668,9 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
R.id.menu_item_visualizer -> {
val active = !visualizerView.isActive
visualizerView.isActive = active
if (!visualizerView.isActive) {
visualizerViewLayout.visibility = View.GONE
} else {
visualizerViewLayout.visibility = View.VISIBLE
}
visualizerViewLayout.isVisible = visualizerView.isActive
mediaPlayerController.showVisualization = visualizerView.isActive
Util.toast(
context,
@ -705,9 +707,8 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
return true
}
R.id.menu_item_star -> {
if (currentSong == null) {
return true
}
if (currentSong == null) return true
val isStarred = currentSong!!.starred
val id = currentSong!!.id
if (isStarred) {
@ -732,9 +733,8 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
return true
}
R.id.menu_item_bookmark_set -> {
if (currentSong == null) {
return true
}
if (currentSong == null) return true
val songId = currentSong!!.id
val playerPosition = mediaPlayerController.playerPosition
currentSong!!.bookmarkPosition = playerPosition
@ -755,9 +755,8 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
return true
}
R.id.menu_item_bookmark_delete -> {
if (currentSong == null) {
return true
}
if (currentSong == null) return true
val bookmarkSongId = currentSong!!.id
currentSong!!.bookmarkPosition = 0
Thread {
@ -782,6 +781,15 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
shareHandler.createShare(this, entries, null, cancellationToken)
return true
}
R.id.menu_item_share_song -> {
if (currentSong == null) return true
val entries: MutableList<MusicDirectory.Entry?> = ArrayList()
entries.add(currentSong)
shareHandler.createShare(this, entries, null, cancellationToken)
return true
}
else -> return false
}
}
@ -903,7 +911,9 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
onCurrentChanged()
}
})
emptyTextView.visibility = if (list.isEmpty()) View.VISIBLE else View.GONE
emptyTextView.isVisible = list.isEmpty()
currentRevision = mediaPlayerController.playListUpdateRevision
when (mediaPlayerController.repeatMode) {
RepeatMode.OFF -> repeatButton.setImageDrawable(
@ -1028,19 +1038,19 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
when (playerState) {
PlayerState.STARTED -> {
pauseButton.visibility = View.VISIBLE
stopButton.visibility = View.GONE
startButton.visibility = View.GONE
pauseButton.isVisible = true
stopButton.isVisible = false
startButton.isVisible = false
}
PlayerState.DOWNLOADING, PlayerState.PREPARING -> {
pauseButton.visibility = View.GONE
stopButton.visibility = View.VISIBLE
startButton.visibility = View.GONE
pauseButton.isVisible = false
stopButton.isVisible = true
startButton.isVisible = false
}
else -> {
pauseButton.visibility = View.GONE
stopButton.visibility = View.GONE
startButton.visibility = View.VISIBLE
pauseButton.isVisible = false
stopButton.isVisible = false
startButton.isVisible = true
}
}

View File

@ -7,6 +7,8 @@ import android.view.LayoutInflater
import android.view.View
import android.widget.CheckBox
import android.widget.EditText
import android.widget.TextView
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import java.util.Locale
@ -31,9 +33,12 @@ import org.moire.ultrasonic.util.TimeSpanPicker
class ShareHandler(val context: Context) {
private var shareDescription: EditText? = null
private var timeSpanPicker: TimeSpanPicker? = null
private var shareOnServerCheckBox: CheckBox? = null
private var hideDialogCheckBox: CheckBox? = null
private var noExpirationCheckBox: CheckBox? = null
private var saveAsDefaultsCheckBox: CheckBox? = null
private var textViewComment: TextView? = null
private var textViewExpiration: TextView? = null
private val pattern = Pattern.compile(":")
fun createShare(
@ -62,15 +67,17 @@ class ShareHandler(val context: Context) {
swipe: SwipeRefreshLayout?,
cancellationToken: CancellationToken
) {
val task: BackgroundTask<Share> = object : FragmentBackgroundTask<Share>(
val task: BackgroundTask<Share?> = object : FragmentBackgroundTask<Share?>(
fragment.requireActivity(),
true,
swipe,
cancellationToken
) {
@Throws(Throwable::class)
override fun doInBackground(): Share {
override fun doInBackground(): Share? {
val ids: MutableList<String> = ArrayList()
if (!shareDetails.ShareOnServer && shareDetails.Entries.size == 1) return null
if (shareDetails.Entries.isEmpty()) {
fragment.arguments?.getString(Constants.INTENT_EXTRA_NAME_ID)?.let {
ids.add(it)
@ -80,23 +87,51 @@ class ShareHandler(val context: Context) {
ids.add(id)
}
}
val musicService = getMusicService()
var timeInMillis: Long = 0
if (shareDetails.Expiration != 0L) {
timeInMillis = shareDetails.Expiration
}
val shares =
musicService.createShare(ids, shareDetails.Description, timeInMillis)
return shares[0]
}
override fun done(result: Share) {
override fun done(result: Share?) {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/plain"
intent.putExtra(
Intent.EXTRA_TEXT,
String.format(Locale.ROOT, "%s\n\n%s", Settings.shareGreeting, result.url)
)
if (result != null) {
// Created a share, send the URL
intent.putExtra(
Intent.EXTRA_TEXT,
String.format(
Locale.ROOT, "%s\n\n%s", Settings.shareGreeting, result.url
)
)
} else {
// Sending only text details
val textBuilder = StringBuilder()
textBuilder.appendLine(Settings.shareGreeting)
if (!shareDetails.Entries[0].title.isNullOrEmpty())
textBuilder.append(context.resources.getString(R.string.common_title))
.append(": ").appendLine(shareDetails.Entries[0].title)
if (!shareDetails.Entries[0].artist.isNullOrEmpty())
textBuilder.append(context.resources.getString(R.string.common_artist))
.append(": ").appendLine(shareDetails.Entries[0].artist)
if (!shareDetails.Entries[0].album.isNullOrEmpty())
textBuilder.append(context.resources.getString(R.string.common_album))
.append(": ").append(shareDetails.Entries[0].album)
intent.putExtra(Intent.EXTRA_TEXT, textBuilder.toString())
}
fragment.activity?.startActivity(
Intent.createChooser(
intent,
@ -119,24 +154,45 @@ class ShareHandler(val context: Context) {
if (layout != null) {
shareDescription = layout.findViewById<View>(R.id.share_description) as EditText
hideDialogCheckBox = layout.findViewById<View>(R.id.hide_dialog) as CheckBox
shareOnServerCheckBox = layout.findViewById<View>(R.id.share_on_server) as CheckBox
noExpirationCheckBox = layout.findViewById<View>(
R.id.timeSpanDisableCheckBox
) as CheckBox
saveAsDefaultsCheckBox = layout.findViewById<View>(R.id.save_as_defaults) as CheckBox
timeSpanPicker = layout.findViewById<View>(R.id.date_picker) as TimeSpanPicker
textViewComment = layout.findViewById<View>(R.id.textViewComment) as TextView
textViewExpiration = layout.findViewById<View>(R.id.textViewExpiration) as TextView
}
if (shareDetails.Entries.size == 1) {
// For single songs the sharing may be done by text only
shareOnServerCheckBox?.setOnCheckedChangeListener { _, _ ->
updateVisibility()
}
shareOnServerCheckBox?.isChecked = Settings.shareOnServer
} else {
shareOnServerCheckBox?.isVisible = false
}
updateVisibility()
val builder = AlertDialog.Builder(fragment.context)
builder.setTitle(R.string.share_set_share_options)
builder.setPositiveButton(R.string.common_save) { _, _ ->
builder.setPositiveButton(R.string.menu_share) { _, _ ->
if (!noExpirationCheckBox!!.isChecked) {
val timeSpan: TimeSpan = timeSpanPicker!!.timeSpan
val now = TimeSpan.getCurrentTime()
shareDetails.Expiration = now.add(timeSpan).totalMilliseconds
}
shareDetails.Description = shareDescription!!.text.toString()
shareDetails.ShareOnServer = shareOnServerCheckBox!!.isChecked
if (hideDialogCheckBox!!.isChecked) {
Settings.shouldAskForShareDetails = false
}
if (saveAsDefaultsCheckBox!!.isChecked) {
val timeSpanType: String = timeSpanPicker!!.timeSpanType
val timeSpanAmount: Int = timeSpanPicker!!.timeSpanAmount
@ -145,22 +201,29 @@ class ShareHandler(val context: Context) {
String.format("%d:%s", timeSpanAmount, timeSpanType) else ""
Settings.defaultShareDescription = shareDetails.Description
Settings.shareOnServer = shareDetails.ShareOnServer
}
share(fragment, shareDetails, swipe, cancellationToken)
}
builder.setNegativeButton(R.string.common_cancel) { dialog, _ ->
dialog.cancel()
}
builder.setView(layout)
builder.setCancelable(true)
timeSpanPicker!!.setTimeSpanDisableText(context.resources.getString(R.string.no_expiration))
noExpirationCheckBox!!.setOnCheckedChangeListener {
_,
b ->
timeSpanPicker!!.isEnabled = !b
}
val defaultDescription = Settings.defaultShareDescription
val timeSpan = Settings.defaultShareExpiration
val split = pattern.split(timeSpan)
if (split.size == 2) {
val timeSpanAmount = split[0].toInt()
@ -178,8 +241,25 @@ class ShareHandler(val context: Context) {
noExpirationCheckBox!!.isChecked = true
timeSpanPicker!!.isEnabled = false
}
shareDescription!!.setText(defaultDescription)
builder.create()
builder.show()
}
private fun updateVisibility() {
if (!shareOnServerCheckBox!!.isVisible || shareOnServerCheckBox!!.isChecked) {
noExpirationCheckBox?.isVisible = true
timeSpanPicker?.isVisible = true
shareDescription?.isVisible = true
textViewComment?.isVisible = true
textViewExpiration?.isVisible = true
} else {
noExpirationCheckBox?.isVisible = false
timeSpanPicker?.isVisible = false
shareDescription?.isVisible = false
textViewComment?.isVisible = false
textViewExpiration?.isVisible = false
}
}
}

View File

@ -105,6 +105,7 @@ object Constants {
const val PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS = "sharingAlwaysAskForDetails"
const val PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION = "sharingDefaultDescription"
const val PREFERENCES_KEY_DEFAULT_SHARE_GREETING = "sharingDefaultGreeting"
const val PREFERENCES_KEY_SHARE_ON_SERVER = "sharingCreateOnServer"
const val PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION = "sharingDefaultExpiration"
const val PREFERENCES_KEY_SHOW_ALL_SONGS_BY_ARTIST = "showAllSongsByArtist"
const val PREFERENCES_KEY_USE_FIVE_STAR_RATING = "use_five_star_rating"

View File

@ -376,6 +376,21 @@ object Settings {
)
}
var shareOnServer: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHARE_ON_SERVER, true)!!
}
set(shareOnServer) {
val preferences = preferences
val editor = preferences.edit()
editor.putBoolean(
Constants.PREFERENCES_KEY_SHARE_ON_SERVER,
shareOnServer
)
editor.apply()
}
var defaultShareExpiration: String
get() {
val preferences = preferences

View File

@ -10,6 +10,14 @@
a:layout_width="wrap_content"
a:layout_height="wrap_content">
<CheckBox
a:id="@+id/share_on_server"
a:text="@string/share_on_server"
a:layout_width="wrap_content"
a:layout_height="wrap_content"
a:layout_marginTop="4dip"
a:layout_marginBottom="4dip" />
<TextView
a:layout_width="wrap_content"
a:layout_height="wrap_content"

View File

@ -14,6 +14,11 @@
a:icon="?attr/star_hollow"
app:showAsAction="ifRoom|withText"
a:title="@string/download.menu_star"/>
<item
a:id="@+id/menu_item_share_song"
a:icon="?attr/share"
app:showAsAction="ifRoom|withText"
a:title="@string/download.share_song"/>
<item
a:id="@+id/menu_item_share"
a:icon="?attr/share"

View File

@ -28,7 +28,9 @@
<string name="button_bar.playlists">Playlists</string>
<string name="button_bar.search">Search</string>
<string name="chat.send_a_message">Send a message</string>
<string name="common.album">Album</string>
<string name="common.appname">Ultrasonic</string>
<string name="common.artist">Artist</string>
<string name="common.cancel">Cancel</string>
<string name="common.comment">Comment</string>
<string name="common.confirm">Confirm</string>
@ -48,6 +50,7 @@
<string name="common.play_shuffled">Play Shuffled</string>
<string name="common.public">Public</string>
<string name="common.save">Save</string>
<string name="common.title">Title</string>
<string name="common.unpin">Unpin</string>
<string name="common.various_artists">Various Artists</string>
<string name="delete_playlist">Do you want to delete %1$s</string>
@ -350,11 +353,13 @@
<string name="widget.sdcard_missing">No SD card</string>
<string name="settings.share_description_default">Default Share Description</string>
<string name="settings.sharing_title">Sharing</string>
<string name="settings.sharing_always_ask_for_details_summary">Always ask for description and expiration when creating a share</string>
<string name="settings.sharing_always_ask_for_details_summary">Always ask for description and expiration when creating a share on the server</string>
<string name="settings.sharing_always_ask_for_details">Always Ask For Details</string>
<string name="settings.share_expiration_default">Default Expiration Time</string>
<string name="do_not_show_dialog_again">Do not show dialog again</string>
<string name="share_set_share_options">Set Share Options</string>
<string name="share_on_server">Create share on the server</string>
<string name="settings.share_on_server_summary">Sharing will create a share on the server and share its URL. If disabled, only the song details are shared</string>
<string name="no_expiration">No Expiration</string>
<string name="download.toggle_playlist">Toggle Playlist</string>
<string name="download.bookmark_set">Set Bookmark</string>
@ -377,6 +382,7 @@
<string name="settings.share_expiration">Time To Expiration</string>
<string name="download_song_removed">\"%s\" was removed from playlist</string>
<string name="download.share_playlist">Share Playlist</string>
<string name="download.share_song">Share Current Song</string>
<string name="settings.share_greeting_default">Default Share Greeting</string>
<string name="share_default_greeting">Check out this music I shared from %s</string>
<string name="share_via">Share songs via</string>

View File

@ -189,18 +189,15 @@
<PreferenceCategory
a:title="@string/settings.sharing_title"
app:iconSpaceReserved="false">
<EditTextPreference
a:key="sharingDefaultDescription"
a:title="@string/settings.share_description_default"
app:iconSpaceReserved="false"/>
<EditTextPreference
a:key="sharingDefaultGreeting"
a:title="@string/settings.share_greeting_default"
app:iconSpaceReserved="false"/>
<org.moire.ultrasonic.util.TimeSpanPreference
a:defaultValue="0"
a:key="sharingDefaultExpiration"
a:title="@string/settings.share_expiration_default"
<CheckBoxPreference
a:defaultValue="true"
a:key="sharingCreateOnServer"
a:title="@string/share_on_server"
a:summary="@string/settings.share_on_server_summary"
app:iconSpaceReserved="false"/>
<CheckBoxPreference
a:defaultValue="true"
@ -208,6 +205,15 @@
a:summary="@string/settings.sharing_always_ask_for_details_summary"
a:title="@string/settings.sharing_always_ask_for_details"
app:iconSpaceReserved="false"/>
<EditTextPreference
a:key="sharingDefaultDescription"
a:title="@string/settings.share_description_default"
app:iconSpaceReserved="false"/>
<org.moire.ultrasonic.util.TimeSpanPreference
a:defaultValue="0"
a:key="sharingDefaultExpiration"
a:title="@string/settings.share_expiration_default"
app:iconSpaceReserved="false"/>
</PreferenceCategory>
<PreferenceCategory
a:title="@string/settings.network_title"