Story creation integration
This commit is contained in:
parent
bb3c9afb13
commit
8703287d90
|
@ -65,6 +65,7 @@ class PostCreationFragment : BaseFragment() {
|
|||
|
||||
// Inflate the layout for this fragment
|
||||
binding = FragmentPostCreationBinding.inflate(layoutInflater)
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
@ -91,11 +92,6 @@ class PostCreationFragment : BaseFragment() {
|
|||
}
|
||||
model = _model
|
||||
|
||||
if(model.storyCreation){
|
||||
binding.carousel.showCaption = false
|
||||
//TODO hide grid button, hide dot (indicator), hide arrows, limit photos to 1
|
||||
}
|
||||
|
||||
model.getPhotoData().observe(viewLifecycleOwner) { newPhotoData ->
|
||||
// update UI
|
||||
binding.carousel.addData(
|
||||
|
@ -107,6 +103,7 @@ class PostCreationFragment : BaseFragment() {
|
|||
)
|
||||
}
|
||||
)
|
||||
binding.postCreationNextButton.isEnabled = newPhotoData.isNotEmpty()
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
|
@ -127,13 +124,26 @@ class PostCreationFragment : BaseFragment() {
|
|||
binding.toolbarPostCreation.visibility =
|
||||
if (uiState.isCarousel) View.VISIBLE else View.INVISIBLE
|
||||
binding.carousel.layoutCarousel = uiState.isCarousel
|
||||
|
||||
if(uiState.storyCreation){
|
||||
binding.toggleStoryPost.check(binding.buttonStory.id)
|
||||
binding.buttonStory.isPressed = true
|
||||
binding.carousel.showLayoutSwitchButton = false
|
||||
binding.carousel.showIndicator = false
|
||||
} else {
|
||||
binding.toggleStoryPost.check(binding.buttonPost.id)
|
||||
binding.carousel.showLayoutSwitchButton = true
|
||||
binding.carousel.showIndicator = true
|
||||
}
|
||||
binding.carousel.maxEntries = uiState.maxEntries
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.carousel.apply {
|
||||
layoutCarouselCallback = { model.becameCarousel(it)}
|
||||
maxEntries = instance.albumLimit
|
||||
maxEntries = if(model.uiState.value.storyCreation) 1 else instance.albumLimit
|
||||
addPhotoButtonCallback = {
|
||||
addPhoto()
|
||||
}
|
||||
|
@ -141,9 +151,10 @@ class PostCreationFragment : BaseFragment() {
|
|||
model.updateDescription(position, description)
|
||||
}
|
||||
}
|
||||
// get the description and send the post
|
||||
binding.postCreationSendButton.setOnClickListener {
|
||||
if (validatePost() && model.isNotEmpty()) {
|
||||
|
||||
// Validate the post and go to the next step of the post creation process
|
||||
binding.postCreationNextButton.setOnClickListener {
|
||||
if (validatePost()) {
|
||||
findNavController().navigate(R.id.action_postCreationFragment_to_postSubmissionFragment)
|
||||
}
|
||||
}
|
||||
|
@ -171,6 +182,23 @@ class PostCreationFragment : BaseFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
binding.toggleStoryPost.addOnButtonCheckedListener { _, checkedId, isChecked ->
|
||||
// Only handle checked events
|
||||
if (!isChecked) return@addOnButtonCheckedListener
|
||||
|
||||
when (checkedId) {
|
||||
R.id.buttonStory -> {
|
||||
model.storyMode(true)
|
||||
}
|
||||
R.id.buttonPost -> {
|
||||
model.storyMode(false)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
binding.backbutton.setOnClickListener{requireActivity().onBackPressedDispatcher.onBackPressed()}
|
||||
|
||||
// Clean up temporary files, if any
|
||||
val tempFiles = requireActivity().intent.getStringArrayExtra(PostCreationActivity.TEMP_FILES)
|
||||
tempFiles?.asList()?.forEach {
|
||||
|
@ -284,8 +312,9 @@ class PostCreationFragment : BaseFragment() {
|
|||
|
||||
private fun validatePost(): Boolean {
|
||||
if (model.getPhotoData().value?.none { it.video && it.videoEncodeComplete == false } == true) {
|
||||
// Encoding is done, i.e. none of the items are both a video and not done encoding
|
||||
return true
|
||||
// Encoding is done, i.e. none of the items are both a video and not done encoding.
|
||||
// We return true if the post is not empty, false otherwise.
|
||||
return model.getPhotoData().value?.isNotEmpty() == true
|
||||
}
|
||||
// Encoding is not done, show a dialog and return false to indicate validation failed
|
||||
MaterialAlertDialogBuilder(requireActivity()).apply {
|
||||
|
|
|
@ -55,7 +55,6 @@ import kotlin.collections.forEach
|
|||
import kotlin.collections.get
|
||||
import kotlin.collections.getOrNull
|
||||
import kotlin.collections.indexOfFirst
|
||||
import kotlin.collections.isNotEmpty
|
||||
import kotlin.collections.mutableListOf
|
||||
import kotlin.collections.mutableMapOf
|
||||
import kotlin.collections.plus
|
||||
|
@ -71,6 +70,7 @@ data class PostCreationActivityUiState(
|
|||
val addPhotoButtonEnabled: Boolean = true,
|
||||
val editPhotoButtonEnabled: Boolean = true,
|
||||
val removePhotoButtonEnabled: Boolean = true,
|
||||
val maxEntries: Int?,
|
||||
|
||||
val isCarousel: Boolean = true,
|
||||
|
||||
|
@ -87,6 +87,11 @@ data class PostCreationActivityUiState(
|
|||
val uploadErrorVisible: Boolean = false,
|
||||
val uploadErrorExplanationText: String = "",
|
||||
val uploadErrorExplanationVisible: Boolean = false,
|
||||
|
||||
val storyCreation: Boolean,
|
||||
val storyDuration: Int = 10,
|
||||
val storyReplies: Boolean = true,
|
||||
val storyReactions: Boolean = true,
|
||||
)
|
||||
|
||||
@Parcelize
|
||||
|
@ -109,8 +114,9 @@ class PostCreationViewModel(
|
|||
val instance: InstanceDatabaseEntity? = null,
|
||||
existingDescription: String? = null,
|
||||
existingNSFW: Boolean = false,
|
||||
val storyCreation: Boolean = false,
|
||||
storyCreation: Boolean = false,
|
||||
) : AndroidViewModel(application) {
|
||||
private var storyPhotoDataBackup: MutableList<PhotoData>? = null
|
||||
private val photoData: MutableLiveData<MutableList<PhotoData>> by lazy {
|
||||
MutableLiveData<MutableList<PhotoData>>().also {
|
||||
it.value = clipdata?.let { it1 -> addPossibleImages(it1, mutableListOf()) }
|
||||
|
@ -130,7 +136,9 @@ class PostCreationViewModel(
|
|||
|
||||
_uiState = MutableStateFlow(PostCreationActivityUiState(
|
||||
newPostDescriptionText = existingDescription ?: templateDescription,
|
||||
nsfw = existingNSFW
|
||||
nsfw = existingNSFW,
|
||||
maxEntries = if(storyCreation) 1 else instance?.albumLimit,
|
||||
storyCreation = storyCreation
|
||||
))
|
||||
}
|
||||
|
||||
|
@ -147,23 +155,27 @@ class PostCreationViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read-only public view on [photoData]
|
||||
*/
|
||||
fun getPhotoData(): LiveData<MutableList<PhotoData>> = photoData
|
||||
|
||||
/**
|
||||
* Will add as many images as possible to [photoData], from the [clipData], and if
|
||||
* ([photoData].size + [clipData].itemCount) > [InstanceDatabaseEntity.albumLimit] then it will only add as many images
|
||||
* ([photoData].size + [clipData].itemCount) > uiState.value.maxEntries then it will only add as many images
|
||||
* as are legal (if any) and a dialog will be shown to the user alerting them of this fact.
|
||||
*/
|
||||
fun addPossibleImages(clipData: ClipData, previousList: MutableList<PhotoData>? = photoData.value): MutableList<PhotoData> {
|
||||
val dataToAdd: ArrayList<PhotoData> = arrayListOf()
|
||||
var count = clipData.itemCount
|
||||
if(count + (previousList?.size ?: 0) > instance!!.albumLimit){
|
||||
uiState.value.maxEntries?.let {
|
||||
if(count + (previousList?.size ?: 0) > it){
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(userMessage = getApplication<PixelDroidApplication>().getString(R.string.total_exceeds_album_limit).format(instance.albumLimit))
|
||||
currentUiState.copy(userMessage = getApplication<PixelDroidApplication>().getString(R.string.total_exceeds_album_limit).format(it))
|
||||
}
|
||||
count = count.coerceAtMost(instance.albumLimit - (previousList?.size ?: 0))
|
||||
count = count.coerceAtMost(it - (previousList?.size ?: 0))
|
||||
}
|
||||
if (count + (previousList?.size ?: 0) >= instance.albumLimit) {
|
||||
if (count + (previousList?.size ?: 0) >= it) {
|
||||
// Disable buttons to add more images
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(addPhotoButtonEnabled = false)
|
||||
|
@ -176,6 +188,8 @@ class PostCreationViewModel(
|
|||
dataToAdd.add(PhotoData(imageUri = it.uri, size = sizeAndVideoPair.first, video = sizeAndVideoPair.second, imageDescription = it.text?.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return previousList?.plus(dataToAdd)?.toMutableList() ?: mutableListOf()
|
||||
}
|
||||
|
||||
|
@ -187,7 +201,7 @@ class PostCreationViewModel(
|
|||
* Returns the size of the file of the Uri, and whether it is a video,
|
||||
* and opens a dialog in case it is too big or in case the file is unsupported.
|
||||
*/
|
||||
fun getSizeAndVideoValidate(uri: Uri, editPosition: Int): Pair<Long, Boolean> {
|
||||
private fun getSizeAndVideoValidate(uri: Uri, editPosition: Int): Pair<Long, Boolean> {
|
||||
val size: Long =
|
||||
if (uri.scheme =="content") {
|
||||
getApplication<PixelDroidApplication>().contentResolver.query(uri, null, null, null, null)
|
||||
|
@ -217,6 +231,7 @@ class PostCreationViewModel(
|
|||
}
|
||||
|
||||
if ((!isVideo && sizeInkBytes > instance!!.maxPhotoSize) || (isVideo && sizeInkBytes > instance!!.maxVideoSize)) {
|
||||
//TODO Offer remedy for too big file: re-compress it
|
||||
val maxSize = if (isVideo) instance.maxVideoSize else instance.maxPhotoSize
|
||||
_uiState.update { currentUiState ->
|
||||
currentUiState.copy(
|
||||
|
@ -227,8 +242,6 @@ class PostCreationViewModel(
|
|||
return Pair(size, isVideo)
|
||||
}
|
||||
|
||||
fun isNotEmpty(): Boolean = photoData.value?.isNotEmpty() ?: false
|
||||
|
||||
fun updateDescription(position: Int, description: String) {
|
||||
photoData.value?.getOrNull(position)?.imageDescription = description
|
||||
photoData.value = photoData.value
|
||||
|
@ -238,7 +251,7 @@ class PostCreationViewModel(
|
|||
photoData.value?.removeAt(currentPosition)
|
||||
_uiState.update {
|
||||
it.copy(
|
||||
addPhotoButtonEnabled = true
|
||||
addPhotoButtonEnabled = (photoData.value?.size ?: 0) < (uiState.value.maxEntries ?: 0),
|
||||
)
|
||||
}
|
||||
photoData.value = photoData.value
|
||||
|
@ -258,7 +271,7 @@ class PostCreationViewModel(
|
|||
videoEncodeProgress = 0
|
||||
videoEncodeComplete = false
|
||||
|
||||
VideoEditActivity.startEncoding(imageUri, it,
|
||||
VideoEditActivity.startEncoding(imageUri, null, it,
|
||||
context = getApplication<PixelDroidApplication>(),
|
||||
registerNewFFmpegSession = ::registerNewFFmpegSession,
|
||||
trackTempFile = ::trackTempFile,
|
||||
|
@ -447,9 +460,8 @@ class PostCreationViewModel(
|
|||
} ?: apiHolder.api ?: apiHolder.setToCurrentUser()
|
||||
|
||||
val inter: Observable<Attachment> =
|
||||
//TODO specify story duration
|
||||
//TODO validate that image is correct (?) aspect ratio
|
||||
if (storyCreation) api.storyUpload(requestBody.parts[0])
|
||||
if (uiState.value.storyCreation) api.storyUpload(requestBody.parts[0])
|
||||
else api.mediaUpload(description, requestBody.parts[0])
|
||||
|
||||
apiHolder.api = null
|
||||
|
@ -459,7 +471,7 @@ class PostCreationViewModel(
|
|||
.subscribe(
|
||||
{ attachment: Attachment ->
|
||||
data.progress = 0
|
||||
data.uploadId = if(storyCreation){
|
||||
data.uploadId = if(uiState.value.storyCreation){
|
||||
attachment.media_id!!
|
||||
} else {
|
||||
attachment.id!!
|
||||
|
@ -519,11 +531,11 @@ class PostCreationViewModel(
|
|||
apiHolder.setToCurrentUser(it)
|
||||
} ?: apiHolder.api ?: apiHolder.setToCurrentUser()
|
||||
|
||||
if(storyCreation){
|
||||
if(uiState.value.storyCreation){
|
||||
api.storyPublish(
|
||||
media_id = getPhotoData().value!!.firstNotNullOf { it.uploadId },
|
||||
can_react = "1", can_reply = "1",
|
||||
duration = 10
|
||||
duration = uiState.value.storyDuration
|
||||
)
|
||||
} else{
|
||||
api.postStatus(
|
||||
|
@ -571,6 +583,44 @@ class PostCreationViewModel(
|
|||
fun chooseAccount(which: UserDatabaseEntity) {
|
||||
_uiState.update { it.copy(chosenAccount = which) }
|
||||
}
|
||||
|
||||
fun storyMode(storyMode: Boolean) {
|
||||
//TODO check ratio of files in story mode? What is acceptable?
|
||||
|
||||
val newMaxEntries = if (storyMode) 1 else instance?.albumLimit
|
||||
var newUiState = _uiState.value.copy(
|
||||
storyCreation = storyMode,
|
||||
maxEntries = newMaxEntries,
|
||||
addPhotoButtonEnabled = (photoData.value?.size ?: 0) < (newMaxEntries ?: 0),
|
||||
)
|
||||
// If switching to story, and there are too many pictures, keep the first and backup the rest
|
||||
if (storyMode && (photoData.value?.size ?: 0) > 1){
|
||||
storyPhotoDataBackup = photoData.value
|
||||
|
||||
photoData.value = photoData.value?.let { mutableListOf(it.firstOrNull()).filterNotNull().toMutableList() }
|
||||
|
||||
//Show message saying extraneous pictures were removed but can be restored
|
||||
newUiState = newUiState.copy(
|
||||
userMessage = getApplication<PixelDroidApplication>().getString(R.string.extraneous_pictures_stories)
|
||||
)
|
||||
}
|
||||
// Restore if backup not null and first value is unchanged
|
||||
else if (storyPhotoDataBackup != null && storyPhotoDataBackup?.firstOrNull() == photoData.value?.firstOrNull()){
|
||||
photoData.value = storyPhotoDataBackup
|
||||
storyPhotoDataBackup = null
|
||||
}
|
||||
_uiState.update { newUiState }
|
||||
}
|
||||
|
||||
fun storyDuration(value: Int) {
|
||||
_uiState.update {
|
||||
it.copy(storyDuration = value)
|
||||
}
|
||||
}
|
||||
|
||||
fun updateStoryReactions(checked: Boolean) { _uiState.update { it.copy(storyReactions = checked) } }
|
||||
|
||||
fun updateStoryReplies(checked: Boolean) { _uiState.update { it.copy(storyReplies = checked) } }
|
||||
}
|
||||
|
||||
class PostCreationViewModelFactory(val application: Application, val clipdata: ClipData, val instance: InstanceDatabaseEntity, val existingDescription: String?, val existingNSFW: Boolean, val storyCreation: Boolean) : ViewModelProvider.Factory {
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.pixeldroid.app.utils.bindingLifecycleAware
|
|||
import org.pixeldroid.app.utils.db.entities.InstanceDatabaseEntity
|
||||
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
|
||||
import org.pixeldroid.app.utils.setSquareImageFromURL
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
class PostSubmissionFragment : BaseFragment() {
|
||||
|
@ -80,12 +81,16 @@ class PostSubmissionFragment : BaseFragment() {
|
|||
binding.nsfwSwitch.isChecked = model.uiState.value.nsfw
|
||||
binding.newPostDescriptionInputField.setText(model.uiState.value.newPostDescriptionText)
|
||||
|
||||
if(model.storyCreation){
|
||||
if(model.uiState.value.storyCreation){
|
||||
binding.nsfwSwitch.visibility = View.GONE
|
||||
binding.postTextInputLayout.visibility = View.GONE
|
||||
binding.privateTitle.visibility = View.GONE
|
||||
binding.postPreview.visibility = View.GONE
|
||||
//TODO show story specific stuff here
|
||||
|
||||
binding.storyOptions.visibility = View.VISIBLE
|
||||
binding.storyDurationSlider.value = model.uiState.value.storyDuration.toFloat()
|
||||
binding.storyRepliesSwitch.isChecked = model.uiState.value.storyReplies
|
||||
binding.storyReactionsSwitch.isChecked = model.uiState.value.storyReactions
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
|
@ -125,13 +130,24 @@ class PostSubmissionFragment : BaseFragment() {
|
|||
binding.nsfwSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
model.updateNSFW(isChecked)
|
||||
}
|
||||
binding.storyRepliesSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
model.updateStoryReplies(isChecked)
|
||||
}
|
||||
binding.storyReactionsSwitch.setOnCheckedChangeListener { _, isChecked ->
|
||||
model.updateStoryReactions(isChecked)
|
||||
}
|
||||
|
||||
binding.postTextInputLayout.counterMaxLength = instance.maxStatusChars
|
||||
|
||||
binding.storyDurationSlider.addOnChangeListener { _, value, _ ->
|
||||
// Responds to when slider's value is changed
|
||||
model.storyDuration(value.roundToInt())
|
||||
}
|
||||
|
||||
setSquareImageFromURL(View(requireActivity()), model.getPhotoData().value?.get(0)?.imageUri.toString(), binding.postPreview)
|
||||
|
||||
// Get the description and send the post
|
||||
binding.postCreationSendButton.setOnClickListener {
|
||||
binding.postSubmissionSendButton.setOnClickListener {
|
||||
if (validatePost()) model.upload()
|
||||
}
|
||||
|
||||
|
@ -190,13 +206,13 @@ class PostSubmissionFragment : BaseFragment() {
|
|||
}
|
||||
|
||||
private fun enableButton(enable: Boolean = true){
|
||||
binding.postCreationSendButton.isEnabled = enable
|
||||
binding.postSubmissionSendButton.isEnabled = enable
|
||||
if(enable){
|
||||
binding.postingProgressBar.visibility = View.GONE
|
||||
binding.postCreationSendButton.visibility = View.VISIBLE
|
||||
binding.postSubmissionSendButton.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.postingProgressBar.visibility = View.VISIBLE
|
||||
binding.postCreationSendButton.visibility = View.GONE
|
||||
binding.postSubmissionSendButton.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -340,7 +340,8 @@ class CameraFragment : BaseFragment() {
|
|||
putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
|
||||
action = Intent.ACTION_GET_CONTENT
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
|
||||
// Don't allow multiple for story
|
||||
putExtra(Intent.EXTRA_ALLOW_MULTIPLE, !addToStory)
|
||||
uploadImageResultContract.launch(
|
||||
Intent.createChooser(this, null)
|
||||
)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="#FFFFFF" android:viewportHeight="24"
|
||||
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
|
||||
</vector>
|
|
@ -11,29 +11,74 @@
|
|||
android:id="@+id/carousel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:showCaption="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/buttonConstraints"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/top_bar"
|
||||
app:showCaption="true" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/buttonConstraints"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/post_creation_send_button"
|
||||
android:id="@+id/top_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:enabled="true"
|
||||
android:text="@string/upload_next_step"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="?attr/actionBarTheme"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/backbutton"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@android:string/cancel"
|
||||
android:src="?attr/homeAsUpIndicator"
|
||||
android:tooltipText='@android:string/cancel'
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||
android:id="@+id/toggleStoryPost"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:checkedButton="@+id/buttonPost"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/post_creation_next_button"
|
||||
app:layout_constraintStart_toEndOf="@id/backbutton"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:selectionRequired="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonStory"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/type_story" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/buttonPost"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/type_post" />
|
||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||
|
||||
<Button
|
||||
style="@style/Widget.Material3.Button.TextButton.Icon"
|
||||
app:icon="@drawable/arrow_forward"
|
||||
app:iconGravity="end"
|
||||
android:id="@+id/post_creation_next_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="true"
|
||||
android:text="@string/continue_post_creation"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
@ -44,7 +89,7 @@
|
|||
android:minHeight="?attr/actionBarSize"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
app:layout_constraintTop_toBottomOf="@id/top_bar">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/savePhotoButton"
|
||||
|
@ -53,8 +98,8 @@
|
|||
android:layout_marginStart="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/save_to_gallery"
|
||||
android:tooltipText='@string/save_to_gallery'
|
||||
android:src="@drawable/download_file_30dp"
|
||||
android:tooltipText='@string/save_to_gallery'
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
@ -66,8 +111,8 @@
|
|||
android:layout_marginStart="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/delete"
|
||||
android:tooltipText='@string/delete'
|
||||
android:src="@drawable/delete_30dp"
|
||||
android:tooltipText='@string/delete'
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/savePhotoButton"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
@ -79,8 +124,8 @@
|
|||
android:layout_marginStart="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/edit"
|
||||
android:tooltipText='@string/edit'
|
||||
android:src="@drawable/ic_baseline_edit_30"
|
||||
android:tooltipText='@string/edit'
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/removePhotoButton"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
@ -92,8 +137,8 @@
|
|||
android:layout_marginEnd="30dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/add_photo"
|
||||
android:tooltipText='@string/add_photo'
|
||||
android:src="@drawable/add_photo_button"
|
||||
android:tooltipText='@string/add_photo'
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
|
|
@ -76,6 +76,7 @@
|
|||
app:layout_constraintHorizontal_bias="0.498"
|
||||
app:layout_constraintStart_toStartOf="@id/upload_error_text_view"
|
||||
app:layout_constraintTop_toBottomOf="@+id/upload_error_text_explanation" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
||||
|
@ -103,7 +104,7 @@
|
|||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/post_creation_send_button"
|
||||
android:id="@+id/post_submission_send_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:enabled="true"
|
||||
|
@ -182,4 +183,84 @@
|
|||
app:layout_constraintStart_toEndOf="@+id/nsfwSwitch"
|
||||
app:layout_constraintTop_toTopOf="@+id/nsfwSwitch" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/storyOptions"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/top_bar"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/story_duration_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:text="@string/story_duration"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
/>
|
||||
|
||||
<com.google.android.material.slider.Slider
|
||||
android:id="@+id/story_duration_slider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:stepSize="1.0"
|
||||
android:valueFrom="3.0"
|
||||
android:valueTo="15.0"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/story_duration_title" />
|
||||
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/storyRepliesSwitch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="@id/story_duration_slider"
|
||||
app:layout_constraintTop_toBottomOf="@+id/story_duration_slider" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/storyRepliesTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Allow replies"
|
||||
android:textStyle="bold"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/storyRepliesSwitch"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@+id/storyRepliesSwitch"
|
||||
app:layout_constraintTop_toTopOf="@+id/storyRepliesSwitch" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/storyReactionsSwitch"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="@id/storyRepliesSwitch"
|
||||
app:layout_constraintTop_toBottomOf="@+id/storyRepliesSwitch" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/storyReactionsTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Allow reactions"
|
||||
android:textStyle="bold"
|
||||
android:padding="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/storyReactionsSwitch"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@+id/storyReactionsSwitch"
|
||||
app:layout_constraintTop_toTopOf="@+id/storyReactionsSwitch"/>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue