Manage instance live configuration: live enabled and allow replay
fixes #11
This commit is contained in:
parent
6031e37959
commit
f9ea80bb3d
@ -5,21 +5,16 @@ import android.os.Bundle
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.ProgressBar
|
import android.widget.ProgressBar
|
||||||
import androidx.activity.result.ActivityResult
|
|
||||||
import androidx.activity.result.ActivityResultCallback
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.databinding.DataBindingUtil
|
import androidx.databinding.DataBindingUtil
|
||||||
import fr.mobdev.peertubelive.R
|
import fr.mobdev.peertubelive.R
|
||||||
import fr.mobdev.peertubelive.databinding.ChannelListBinding
|
import fr.mobdev.peertubelive.databinding.CreateLiveBinding
|
||||||
import fr.mobdev.peertubelive.manager.DatabaseManager
|
import fr.mobdev.peertubelive.manager.DatabaseManager
|
||||||
import fr.mobdev.peertubelive.manager.InstanceManager
|
import fr.mobdev.peertubelive.manager.InstanceManager
|
||||||
import fr.mobdev.peertubelive.objects.ChannelData
|
import fr.mobdev.peertubelive.objects.*
|
||||||
import fr.mobdev.peertubelive.objects.OAuthData
|
|
||||||
import fr.mobdev.peertubelive.objects.StreamData
|
|
||||||
import fr.mobdev.peertubelive.objects.StreamSettings
|
|
||||||
import fr.mobdev.peertubelive.utils.TranslationUtils
|
import fr.mobdev.peertubelive.utils.TranslationUtils
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
@ -35,9 +30,10 @@ class CreateLiveActivity : AppCompatActivity() {
|
|||||||
private lateinit var privacies: MutableMap<String, Int>
|
private lateinit var privacies: MutableMap<String, Int>
|
||||||
private lateinit var languages: MutableMap<String, String>
|
private lateinit var languages: MutableMap<String, String>
|
||||||
private lateinit var oAuthData: OAuthData
|
private lateinit var oAuthData: OAuthData
|
||||||
|
private lateinit var configData: ConfigData
|
||||||
private var inError: Boolean = false
|
private var inError: Boolean = false
|
||||||
private var showAdvancedSettings = true
|
private var showAdvancedSettings = true
|
||||||
private lateinit var binding: ChannelListBinding
|
private lateinit var binding: CreateLiveBinding
|
||||||
private lateinit var startLive: ActivityResultLauncher<Intent>
|
private lateinit var startLive: ActivityResultLauncher<Intent>
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -45,7 +41,7 @@ class CreateLiveActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
oAuthData = intent.getParcelableExtra(OAUTH_DATA)!!
|
oAuthData = intent.getParcelableExtra(OAUTH_DATA)!!
|
||||||
|
|
||||||
binding = DataBindingUtil.setContentView(this,R.layout.channel_list)
|
binding = DataBindingUtil.setContentView(this,R.layout.create_live)
|
||||||
|
|
||||||
binding.error.visibility = View.GONE
|
binding.error.visibility = View.GONE
|
||||||
binding.channelList.visibility = View.GONE
|
binding.channelList.visibility = View.GONE
|
||||||
@ -60,6 +56,7 @@ class CreateLiveActivity : AppCompatActivity() {
|
|||||||
binding.saveReplayInfo.visibility = View.GONE
|
binding.saveReplayInfo.visibility = View.GONE
|
||||||
binding.resolution.visibility = View.GONE
|
binding.resolution.visibility = View.GONE
|
||||||
binding.resolutionList.visibility = View.GONE
|
binding.resolutionList.visibility = View.GONE
|
||||||
|
binding.liveDisabled.visibility = View.GONE
|
||||||
|
|
||||||
startLive = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
startLive = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||||
setResult(it.resultCode)
|
setResult(it.resultCode)
|
||||||
@ -93,7 +90,9 @@ class CreateLiveActivity : AppCompatActivity() {
|
|||||||
val comments = binding.commentsEnabled.isChecked
|
val comments = binding.commentsEnabled.isChecked
|
||||||
val download = binding.downloadEnabled.isChecked
|
val download = binding.downloadEnabled.isChecked
|
||||||
val nsfw = binding.nsfw.isChecked
|
val nsfw = binding.nsfw.isChecked
|
||||||
val replay = binding.saveReplay.isChecked
|
var replay: Boolean? = null
|
||||||
|
if (configData.saveReplayEnabled)
|
||||||
|
replay = binding.saveReplay.isChecked
|
||||||
|
|
||||||
val resolution = StreamData.STREAM_RESOLUTION.values()[binding.resolutionList.selectedItemPosition]
|
val resolution = StreamData.STREAM_RESOLUTION.values()[binding.resolutionList.selectedItemPosition]
|
||||||
|
|
||||||
@ -108,6 +107,22 @@ class CreateLiveActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstanceManager.getLiveConfig(this,oAuthData.baseUrl!!,object : InstanceManager.InstanceListener {
|
||||||
|
override fun onSuccess(args: Bundle?) {
|
||||||
|
configData = args?.getParcelable<ConfigData>(InstanceManager.EXTRA_DATA)!!
|
||||||
|
updateView(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(error: String?) {
|
||||||
|
inError = true
|
||||||
|
updateView(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUpdateOAuthData(oauthData: OAuthData) {
|
||||||
|
this@CreateLiveActivity.oAuthData.updateData(oauthData)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
InstanceManager.getCategoryList(this,oAuthData.baseUrl!!,object : InstanceManager.InstanceListener {
|
InstanceManager.getCategoryList(this,oAuthData.baseUrl!!,object : InstanceManager.InstanceListener {
|
||||||
override fun onSuccess(args: Bundle?) {
|
override fun onSuccess(args: Bundle?) {
|
||||||
val map = args?.getSerializable(InstanceManager.EXTRA_DATA)!! as Map<String, Int>
|
val map = args?.getSerializable(InstanceManager.EXTRA_DATA)!! as Map<String, Int>
|
||||||
@ -223,7 +238,16 @@ class CreateLiveActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private fun updateView(error: String?) {
|
private fun updateView(error: String?) {
|
||||||
if(!inError) {
|
if(!inError) {
|
||||||
if(this::channels.isInitialized && this::categories.isInitialized && this::privacies.isInitialized && this::languages.isInitialized && this::licences.isInitialized) {
|
if (this::configData.isInitialized && !configData.liveEnabled) {
|
||||||
|
runOnUiThread {
|
||||||
|
binding.loadingProgress.visibility = View.GONE
|
||||||
|
binding.loadingChannels.visibility = View.GONE
|
||||||
|
binding.liveDisabled.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(this::configData.isInitialized && configData.liveEnabled && this::channels.isInitialized && this::categories.isInitialized
|
||||||
|
&& this::privacies.isInitialized && this::languages.isInitialized && this::licences.isInitialized) {
|
||||||
val channelAdapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item)
|
val channelAdapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item)
|
||||||
for (channel in channels) {
|
for (channel in channels) {
|
||||||
channelAdapter.add(channel.name)
|
channelAdapter.add(channel.name)
|
||||||
@ -264,8 +288,10 @@ class CreateLiveActivity : AppCompatActivity() {
|
|||||||
binding.advanceSettings.visibility = View.VISIBLE
|
binding.advanceSettings.visibility = View.VISIBLE
|
||||||
binding.privacy.visibility = View.VISIBLE
|
binding.privacy.visibility = View.VISIBLE
|
||||||
binding.privacyList.visibility = View.VISIBLE
|
binding.privacyList.visibility = View.VISIBLE
|
||||||
|
if (configData.saveReplayEnabled) {
|
||||||
binding.saveReplayLayout.visibility = View.VISIBLE
|
binding.saveReplayLayout.visibility = View.VISIBLE
|
||||||
binding.saveReplayInfo.visibility = View.VISIBLE
|
binding.saveReplayInfo.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
binding.resolution.visibility = View.VISIBLE
|
binding.resolution.visibility = View.VISIBLE
|
||||||
binding.resolutionList.visibility = View.VISIBLE
|
binding.resolutionList.visibility = View.VISIBLE
|
||||||
restoreSettings()
|
restoreSettings()
|
||||||
@ -346,6 +372,7 @@ class CreateLiveActivity : AppCompatActivity() {
|
|||||||
binding.commentsEnabled.isChecked = settings.comments
|
binding.commentsEnabled.isChecked = settings.comments
|
||||||
binding.downloadEnabled.isChecked = settings.download
|
binding.downloadEnabled.isChecked = settings.download
|
||||||
binding.nsfw.isChecked = settings.nsfw
|
binding.nsfw.isChecked = settings.nsfw
|
||||||
|
if (settings.saveReplay != null)
|
||||||
binding.saveReplay.isChecked = settings.saveReplay
|
binding.saveReplay.isChecked = settings.saveReplay
|
||||||
binding.liveTitle.setText(settings.title)
|
binding.liveTitle.setText(settings.title)
|
||||||
|
|
||||||
|
@ -330,7 +330,6 @@ class StreamActivity : AppCompatActivity() {
|
|||||||
if (rtmpCamera2.prepareAudio() && rtmpCamera2.prepareVideo(width,height,30, (width*height*30*0.076).toInt(),false,CameraHelper.getCameraOrientation(this))) {
|
if (rtmpCamera2.prepareAudio() && rtmpCamera2.prepareVideo(width,height,30, (width*height*30*0.076).toInt(),false,CameraHelper.getCameraOrientation(this))) {
|
||||||
rtmpCamera2.startStream(streamData.url+"/"+streamData.key)
|
rtmpCamera2.startStream(streamData.url+"/"+streamData.key)
|
||||||
} else {
|
} else {
|
||||||
println("error")
|
|
||||||
/**This device cant init encoders, this could be for 2 reasons: The encoder selected doesnt support any configuration setted or your device hasnt a H264 or AAC encoder (in this case you can see log error valid encoder not found) */
|
/**This device cant init encoders, this could be for 2 reasons: The encoder selected doesnt support any configuration setted or your device hasnt a H264 or AAC encoder (in this case you can see log error valid encoder not found) */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,7 @@ package fr.mobdev.peertubelive.manager
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import fr.mobdev.peertubelive.R
|
import fr.mobdev.peertubelive.R
|
||||||
import fr.mobdev.peertubelive.objects.ChannelData
|
import fr.mobdev.peertubelive.objects.*
|
||||||
import fr.mobdev.peertubelive.objects.OAuthData
|
|
||||||
import fr.mobdev.peertubelive.objects.StreamData
|
|
||||||
import fr.mobdev.peertubelive.objects.StreamSettings
|
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -25,6 +22,7 @@ object InstanceManager {
|
|||||||
private const val GET_PRIVACY_ENDPOINT: String = "/videos/privacies"
|
private const val GET_PRIVACY_ENDPOINT: String = "/videos/privacies"
|
||||||
private const val GET_LICENCE_ENDPOINT: String = "/videos/licences"
|
private const val GET_LICENCE_ENDPOINT: String = "/videos/licences"
|
||||||
private const val GET_LANGUAGES_ENDPOINT: String = "/videos/languages"
|
private const val GET_LANGUAGES_ENDPOINT: String = "/videos/languages"
|
||||||
|
private const val GET_CONFIG_ENDPOINT: String = "/config"
|
||||||
private const val GET_VIDEOS: String = "/users/me/videos"
|
private const val GET_VIDEOS: String = "/users/me/videos"
|
||||||
|
|
||||||
internal const val EXTRA_DATA: String = "EXTRA_DATA"
|
internal const val EXTRA_DATA: String = "EXTRA_DATA"
|
||||||
@ -38,6 +36,9 @@ object InstanceManager {
|
|||||||
private const val UUID: String = "uuid"
|
private const val UUID: String = "uuid"
|
||||||
private const val RTMP_URL: String = "rtmpUrl"
|
private const val RTMP_URL: String = "rtmpUrl"
|
||||||
private const val STREAM_KEY: String = "streamKey"
|
private const val STREAM_KEY: String = "streamKey"
|
||||||
|
private const val CONFIG_LIVE: String = "live"
|
||||||
|
private const val CONFIG_LIVE_ENABLED: String = "enabled"
|
||||||
|
private const val CONFIG_LIVE_SAVE_REPLAY: String = "allowReplay"
|
||||||
|
|
||||||
fun registerAccount(context: Context, url: String, username: String, password: String, listener: InstanceListener) {
|
fun registerAccount(context: Context, url: String, username: String, password: String, listener: InstanceListener) {
|
||||||
val registerUrl = url + BASE_API_ENDPOINT+ REGISTER_CLIENT_ENDPOINT
|
val registerUrl = url + BASE_API_ENDPOINT+ REGISTER_CLIENT_ENDPOINT
|
||||||
@ -148,7 +149,8 @@ object InstanceManager {
|
|||||||
formData += prepareFormData(boundary,"licence",streamSettings.licence.toString(),false)
|
formData += prepareFormData(boundary,"licence",streamSettings.licence.toString(),false)
|
||||||
formData += prepareFormData(boundary,"commentsEnabled",streamSettings.comments.toString(),false)
|
formData += prepareFormData(boundary,"commentsEnabled",streamSettings.comments.toString(),false)
|
||||||
formData += prepareFormData(boundary,"nsfw",streamSettings.nsfw.toString(),false)
|
formData += prepareFormData(boundary,"nsfw",streamSettings.nsfw.toString(),false)
|
||||||
formData += prepareFormData(boundary,"downloadEnabled",streamSettings.download.toString(),false)
|
formData += prepareFormData(boundary,"downloadEnabled",streamSettings.download.toString(),streamSettings.saveReplay == null)
|
||||||
|
if (streamSettings.saveReplay != null)
|
||||||
formData += prepareFormData(boundary,"saveReplay",streamSettings.saveReplay.toString(),true)
|
formData += prepareFormData(boundary,"saveReplay",streamSettings.saveReplay.toString(),true)
|
||||||
data.putString(CONTENT_TYPE,"multipart/form-data; boundary=$boundary")
|
data.putString(CONTENT_TYPE,"multipart/form-data; boundary=$boundary")
|
||||||
data.putString(CONTENT_DATA,formData)
|
data.putString(CONTENT_DATA,formData)
|
||||||
@ -365,6 +367,36 @@ object InstanceManager {
|
|||||||
oauthManager.get(context,userInfoUrl,null,internalListener)
|
oauthManager.get(context,userInfoUrl,null,internalListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getLiveConfig(context: Context, url: String, listener: InstanceListener) {
|
||||||
|
val userInfoUrl: String = url + BASE_API_ENDPOINT + GET_CONFIG_ENDPOINT
|
||||||
|
val internalListener : InstanceListener = object : InstanceListener {
|
||||||
|
override fun onSuccess(args: Bundle?) {
|
||||||
|
val response = args?.getString(EXTRA_DATA, null)
|
||||||
|
if (response == null) {
|
||||||
|
listener.onError(context.getString(R.string.unknwon_error))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val configData = extractConfigData(response)
|
||||||
|
if (configData == null) {
|
||||||
|
listener.onError(context.getString(R.string.json_error))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
args.putParcelable(EXTRA_DATA, configData)
|
||||||
|
listener.onSuccess(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(error: String?) {
|
||||||
|
listener.onError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUpdateOAuthData(oauthData: OAuthData) {
|
||||||
|
listener.onUpdateOAuthData(oauthData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oauthManager.get(context,userInfoUrl,null,internalListener)
|
||||||
|
}
|
||||||
|
|
||||||
private fun extractChannelData(response: String): ArrayList<ChannelData>? {
|
private fun extractChannelData(response: String): ArrayList<ChannelData>? {
|
||||||
try {
|
try {
|
||||||
val json = JSONObject(response)
|
val json = JSONObject(response)
|
||||||
@ -433,6 +465,28 @@ object InstanceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun extractConfigData(response: String): ConfigData? {
|
||||||
|
try {
|
||||||
|
val json = JSONObject(response)
|
||||||
|
|
||||||
|
return if (json.has(CONFIG_LIVE)) {
|
||||||
|
val live = json.getJSONObject(CONFIG_LIVE)
|
||||||
|
return if(live.has(CONFIG_LIVE_ENABLED) && live.has(CONFIG_LIVE_SAVE_REPLAY)) {
|
||||||
|
val liveEnabled = live.getBoolean(CONFIG_LIVE_ENABLED)
|
||||||
|
val saveReplayEnabled = live.getBoolean(CONFIG_LIVE_SAVE_REPLAY)
|
||||||
|
ConfigData(liveEnabled,saveReplayEnabled)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun <T> extractMapData(response: String, type: T): HashMap<String,T>? {
|
private fun <T> extractMapData(response: String, type: T): HashMap<String,T>? {
|
||||||
return try {
|
return try {
|
||||||
val json = JSONObject(response)
|
val json = JSONObject(response)
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package fr.mobdev.peertubelive.objects;
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
|
||||||
|
class ConfigData(val liveEnabled: Boolean, val saveReplayEnabled: Boolean) : Parcelable {
|
||||||
|
constructor(parcel: Parcel) : this(
|
||||||
|
parcel.readByte() != 0.toByte(),
|
||||||
|
parcel.readByte() != 0.toByte()
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun describeContents(): Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
|
dest.writeByte(if (liveEnabled) 1 else 0)
|
||||||
|
dest.writeByte(if (saveReplayEnabled) 1 else 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object CREATOR : Parcelable.Creator<StreamData> {
|
||||||
|
override fun createFromParcel(parcel: Parcel): StreamData {
|
||||||
|
return StreamData(parcel)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun newArray(size: Int): Array<StreamData?> {
|
||||||
|
return arrayOfNulls(size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ import android.os.Parcelable
|
|||||||
|
|
||||||
class StreamSettings(
|
class StreamSettings(
|
||||||
val title: String, val channel: Long, val privacy: Int, val category: Int?, val language: String?, val licence: Int?, val description: String?,
|
val title: String, val channel: Long, val privacy: Int, val category: Int?, val language: String?, val licence: Int?, val description: String?,
|
||||||
val comments: Boolean, val download: Boolean, val nsfw: Boolean, val saveReplay: Boolean, val resolution: StreamData.STREAM_RESOLUTION) : Parcelable {
|
val comments: Boolean, val download: Boolean, val nsfw: Boolean, val saveReplay: Boolean?, val resolution: StreamData.STREAM_RESOLUTION) : Parcelable {
|
||||||
constructor(parcel: Parcel) : this(
|
constructor(parcel: Parcel) : this(
|
||||||
parcel.readString()!!,
|
parcel.readString()!!,
|
||||||
parcel.readLong(),
|
parcel.readLong(),
|
||||||
@ -37,6 +37,7 @@ class StreamSettings(
|
|||||||
parcel.writeByte(if (comments) 1 else 0)
|
parcel.writeByte(if (comments) 1 else 0)
|
||||||
parcel.writeByte(if (download) 1 else 0)
|
parcel.writeByte(if (download) 1 else 0)
|
||||||
parcel.writeByte(if (nsfw) 1 else 0)
|
parcel.writeByte(if (nsfw) 1 else 0)
|
||||||
|
if (saveReplay!= null)
|
||||||
parcel.writeByte(if (saveReplay) 1 else 0)
|
parcel.writeByte(if (saveReplay) 1 else 0)
|
||||||
parcel.writeInt(resolution?.ordinal!!)
|
parcel.writeInt(resolution?.ordinal!!)
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,18 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
/>
|
/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/live_disabled"
|
||||||
|
android:textColor="#FF0000"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/live_disabled"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
android:layout_margin="5dp"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/error"
|
android:id="@+id/error"
|
@ -26,6 +26,7 @@
|
|||||||
<string name="stop_reason">Votre direct est terminé</string>
|
<string name="stop_reason">Votre direct est terminé</string>
|
||||||
<string name="ask_end_stream">Voulez-vous arrêter le direct \?</string>
|
<string name="ask_end_stream">Voulez-vous arrêter le direct \?</string>
|
||||||
<string name="network_reason">Votre direct s\'est terminé à cause d\'un problème réseau</string>
|
<string name="network_reason">Votre direct s\'est terminé à cause d\'un problème réseau</string>
|
||||||
|
<string name="live_disabled">Cette instance a désactivé les directs.</string>
|
||||||
<!-- buttons -->
|
<!-- buttons -->
|
||||||
<string name="choose_channel">Chaîne</string>
|
<string name="choose_channel">Chaîne</string>
|
||||||
<string name="go_live">Démarrer le direct !</string>
|
<string name="go_live">Démarrer le direct !</string>
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
<string name="stop_reason">Your livestream ended</string>
|
<string name="stop_reason">Your livestream ended</string>
|
||||||
<string name="ask_end_stream">Do you want to stop the live?</string>
|
<string name="ask_end_stream">Do you want to stop the live?</string>
|
||||||
<string name="network_reason">Your livestream ended because of a network problem</string>
|
<string name="network_reason">Your livestream ended because of a network problem</string>
|
||||||
|
<string name="live_disabled">This instance has disabled livestream.</string>
|
||||||
<!-- buttons -->
|
<!-- buttons -->
|
||||||
<string name="choose_channel">Channel</string>
|
<string name="choose_channel">Channel</string>
|
||||||
<string name="go_live">Start livestream</string>
|
<string name="go_live">Start livestream</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user