Add upload progress bars and error handling to PostCreationActivity (#191)
* Add upload bar to PostCreationActivity * Add upload error handling * Fix test, remove duplicate api endpoint * try to trigger ci * don't show error all the time * remove unused strings
This commit is contained in:
parent
5b0a344236
commit
d942c30898
|
@ -123,6 +123,7 @@ dependencies {
|
|||
|
||||
//iconics
|
||||
implementation "com.mikepenz:materialdrawer-iconics:8.0.3"
|
||||
implementation "com.mikepenz:iconics-views:5.0.2"
|
||||
implementation 'com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar'
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package com.h.pixeldroid
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.test.core.app.ActivityScenario
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.*
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.action.ViewActions.swipeLeft
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.intent.Intents.intended
|
||||
import androidx.test.espresso.intent.Intents.intending
|
||||
|
@ -12,7 +12,6 @@ import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
|
|||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.rule.GrantPermissionRule
|
||||
|
@ -22,7 +21,6 @@ import com.h.pixeldroid.db.UserDatabaseEntity
|
|||
import com.h.pixeldroid.testUtility.MockServer
|
||||
import com.h.pixeldroid.utils.DBUtils
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import kotlinx.android.synthetic.main.camera_ui_container.*
|
||||
import org.hamcrest.Matcher
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
|
@ -67,9 +65,6 @@ class PostFragmentUITests {
|
|||
|
||||
@get:Rule
|
||||
var globalTimeout: Timeout = Timeout.seconds(30)
|
||||
@get:Rule
|
||||
var rule = ActivityScenarioRule(MainActivity::class.java)
|
||||
|
||||
private lateinit var db: AppDatabase
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.h.pixeldroid.testUtility
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.h.pixeldroid.objects.Application
|
||||
|
||||
class JsonValues {
|
||||
companion object {
|
||||
const val likedJson = """{"id":"156491373246287872","created_at":"2020-04-16T20:00:50.000000Z","in_reply_to_id":null,"in_reply_to_account_id":null,"sensitive":false,"spoiler_text":"","visibility":"public","language":"en","uri":"https:\/\/pixelfed.de\/p\/machintuck\/156491373246287872","url":"https:\/\/pixelfed.de\/p\/machintuck\/156491373246287872","replies_count":1,"reblogs_count":13,"favourites_count":3,"reblogged":false,"favourited":true,"muted":false,"bookmarked":false,"pinned":false,"content":"<a class=\"u-url mention\" href=\"https:\/\/pixelfed.de\/Dobios\" rel=\"external nofollow noopener\">@Dobios<\/a> <a class=\"u-url mention\" href=\"https:\/\/pixelfed.de\/Dante\" rel=\"external nofollow noopener\">@Dante<\/a>","reblog":null,"application":{"name":"web","website":null},"mentions":[{"id":"136800034732773376","url":"https:\/\/pixelfed.de\/Dobios","username":"Dobios","acct":"Dobios"},{"id":"136453537340198912","url":"https:\/\/pixelfed.de\/dante","username":"dante","acct":"dante"}],"tags":[{"name":"mushroom","url":"https:\/\/pixelfed.de\/discover\/tags\/mushroom"},{"name":"commentsstillbroken","url":"https:\/\/pixelfed.de\/discover\/tags\/commentsstillbroken"},{"name":"fixyourapi","url":"https:\/\/pixelfed.de\/discover\/tags\/fixyourapi"},{"name":"pls","url":"https:\/\/pixelfed.de\/discover\/tags\/pls"}],"emojis":[],"card":null,"poll":null,"account":{"id":"145183325781364736","username":"machintuck","acct":"machintuck","display_name":"Arthur","locked":false,"created_at":"2020-03-16T15:06:42.000000Z","followers_count":4,"following_count":4,"statuses_count":5,"note":"","url":"https:\/\/pixelfed.de\/machintuck","avatar":"https:\/\/pixelfed.de\/storage\/avatars\/014\/518\/332\/578\/136\/473\/6\/gbdKtKOhTkNA5UxCzeAQ_avatar.jpeg?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35","avatar_static":"https:\/\/pixelfed.de\/storage\/avatars\/014\/518\/332\/578\/136\/473\/6\/gbdKtKOhTkNA5UxCzeAQ_avatar.jpeg?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35","header":"","header_static":"","emojis":[],"moved":null,"fields":null,"bot":false,"software":"pixelfed","is_admin":false},"media_attachments":[{"id":"19228","type":"image","url":"https:\/\/pixelfed.de\/storage\/m\/d0931bf747b992a1c83e055753526516f2706111\/9b4393bfd32c643a265bd1c557b981f167d60969\/lbOqQOMeHLGmhYgehhZUBJ4JvjtKulh83BA97LoP.jpeg","remote_url":null,"preview_url":"https:\/\/pixelfed.de\/storage\/m\/d0931bf747b992a1c83e055753526516f2706111\/9b4393bfd32c643a265bd1c557b981f167d60969\/lbOqQOMeHLGmhYgehhZUBJ4JvjtKulh83BA97LoP_thumb.jpeg","text_url":null,"meta":null,"description":null}]}"""
|
||||
|
@ -175,5 +178,8 @@ class JsonValues {
|
|||
"version": "69.420",
|
||||
"registrations": true
|
||||
}"""
|
||||
var applicationJson = Gson().toJson(Application(name="PixelDroid",
|
||||
website=null, vapid_key=null, client_id="286",
|
||||
client_secret="2q3dHY29U8GNZ2eY6cbcw010cWk3qVGmWXxAJzn7"))
|
||||
}
|
||||
}
|
|
@ -45,6 +45,11 @@ class MockServer {
|
|||
.setResponseCode(200).setBody(JsonValues.tokenJson)
|
||||
}
|
||||
when {
|
||||
request.path?.startsWith("/api/v1/apps") == true -> {
|
||||
return MockResponse()
|
||||
.addHeader("Content-Type", "application/json; charset=utf-8")
|
||||
.setResponseCode(200).setBody(JsonValues.applicationJson)
|
||||
}
|
||||
request.path?.startsWith("/api/v1/notifications") == true -> {
|
||||
return MockResponse()
|
||||
.addHeader("Content-Type", "application/json; charset=utf-8")
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
|
||||
<activity android:name=".PostCreationActivity"
|
||||
android:screenOrientation="sensorPortrait"
|
||||
tools:ignore="LockedOrientationActivity" />
|
||||
tools:ignore="LockedOrientationActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar"/>
|
||||
<activity android:name=".FollowsActivity"
|
||||
android:screenOrientation="sensorPortrait"
|
||||
tools:ignore="LockedOrientationActivity"/>
|
||||
|
|
|
@ -5,8 +5,9 @@ import android.graphics.Bitmap
|
|||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
|
@ -15,25 +16,27 @@ import androidx.core.net.toUri
|
|||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.h.pixeldroid.api.PixelfedAPI
|
||||
import com.h.pixeldroid.db.UserDatabaseEntity
|
||||
import com.h.pixeldroid.objects.Attachment
|
||||
import com.h.pixeldroid.objects.Instance
|
||||
import com.h.pixeldroid.objects.Status
|
||||
import com.h.pixeldroid.utils.DBUtils
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import kotlinx.android.synthetic.main.activity_post_creation.*
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okio.BufferedSink
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
import retrofit2.Response
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.io.*
|
||||
|
||||
class PostCreationActivity : AppCompatActivity() {
|
||||
|
||||
class PostCreationActivity : AppCompatActivity(){
|
||||
|
||||
private val TAG = "Post Creation Activity"
|
||||
|
||||
|
@ -43,6 +46,8 @@ class PostCreationActivity : AppCompatActivity() {
|
|||
private lateinit var image: File
|
||||
private var user: UserDatabaseEntity? = null
|
||||
|
||||
private var listOfIds: List<String> = emptyList()
|
||||
|
||||
private var maxLength: Int = Instance.DEFAULT_MAX_TOOT_CHARS
|
||||
|
||||
private var description: String = ""
|
||||
|
@ -77,21 +82,28 @@ class PostCreationActivity : AppCompatActivity() {
|
|||
accessToken = user?.accessToken.orEmpty()
|
||||
pixelfedAPI = PixelfedAPI.create(domain)
|
||||
|
||||
// check if the picture is alright
|
||||
// TODO
|
||||
//upload the picture and display progress while doing so
|
||||
upload()
|
||||
|
||||
// edit the picture
|
||||
// TODO
|
||||
|
||||
// get the description and send the post to PixelFed
|
||||
// get the description and send the post
|
||||
findViewById<Button>(R.id.post_creation_send_button).setOnClickListener {
|
||||
if (setDescription()) upload()
|
||||
if (setDescription() && listOfIds.isNotEmpty()) post()
|
||||
}
|
||||
|
||||
// Button to retry image upload when it fails
|
||||
findViewById<Button>(R.id.retry_upload_button).setOnClickListener {
|
||||
upload_error.visibility = GONE
|
||||
upload()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
//delete the temporary image
|
||||
image.delete()
|
||||
}
|
||||
|
||||
private fun saveImage(imageUri: Uri) {
|
||||
val timeStamp: String = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
|
||||
val fileName = "PixelDroid_$timeStamp.png"
|
||||
try {
|
||||
val stream = applicationContext.contentResolver
|
||||
.openAssetFileDescriptor(imageUri, "r")!!
|
||||
|
@ -99,9 +111,8 @@ class PostCreationActivity : AppCompatActivity() {
|
|||
val bm = BitmapFactory.decodeStream(stream)
|
||||
val bos = ByteArrayOutputStream()
|
||||
bm.compress(Bitmap.CompressFormat.PNG, 0, bos)
|
||||
image = File(
|
||||
applicationContext.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
|
||||
fileName)
|
||||
image = File.createTempFile("temp_compressed_img", ".png", cacheDir)
|
||||
|
||||
val fos = FileOutputStream(image)
|
||||
fos.write(bos.toByteArray())
|
||||
fos.flush()
|
||||
|
@ -116,7 +127,7 @@ class PostCreationActivity : AppCompatActivity() {
|
|||
val textField = findViewById<TextInputEditText>(R.id.new_post_description_input_field)
|
||||
val content = textField.text.toString()
|
||||
if (content.length > maxLength) {
|
||||
// error, too much characters
|
||||
// error, too many characters
|
||||
textField.error = getString(R.string.description_max_characters).format(maxLength)
|
||||
|
||||
return false
|
||||
|
@ -126,44 +137,50 @@ class PostCreationActivity : AppCompatActivity() {
|
|||
return true
|
||||
}
|
||||
|
||||
private fun upload() {
|
||||
val rBody: RequestBody = image.asRequestBody("image/*".toMediaTypeOrNull())
|
||||
val part = MultipartBody.Part.createFormData("file", image.name, rBody)
|
||||
pixelfedAPI.mediaUpload("Bearer $accessToken", part).enqueue(object:
|
||||
Callback<Attachment> {
|
||||
override fun onFailure(call: Call<Attachment>, t: Throwable) {
|
||||
Log.e(TAG, t.toString() + call.request())
|
||||
Toast.makeText(applicationContext,getString(R.string.upload_picture_failed),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
private fun upload(){
|
||||
val imagePart = ProgressRequestBody(image)
|
||||
val requestBody = MultipartBody.Builder()
|
||||
.setType(MultipartBody.FORM)
|
||||
.addFormDataPart("file", image.name, imagePart)
|
||||
.build()
|
||||
|
||||
val sub = imagePart.progressSubject
|
||||
.subscribeOn(Schedulers.io())
|
||||
.subscribe { percentage ->
|
||||
uploadProgressBar.progress = percentage.toInt()
|
||||
}
|
||||
|
||||
override fun onResponse(call: Call<Attachment>, response: Response<Attachment>) {
|
||||
if (response.code() == 200) {
|
||||
val body = response.body()!!
|
||||
if (body.type.name == "image") {
|
||||
post(body.id)
|
||||
} else
|
||||
Toast.makeText(applicationContext, getString(R.string.picture_format_error),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
Log.e(TAG,
|
||||
"Server responded: $response${call.request()}${call.request().body}"
|
||||
)
|
||||
Toast.makeText(applicationContext,getString(R.string.request_format_error),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
})
|
||||
var postSub : Disposable?= null
|
||||
val inter = pixelfedAPI.mediaUpload("Bearer $accessToken", requestBody.parts[0])
|
||||
|
||||
postSub = inter
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ attachment ->
|
||||
listOfIds = listOf(attachment.id)
|
||||
},{e->
|
||||
upload_error.visibility = VISIBLE
|
||||
e.printStackTrace()
|
||||
postSub?.dispose()
|
||||
sub.dispose()
|
||||
}, {
|
||||
uploadProgressBar.visibility = GONE
|
||||
upload_completed_textview.visibility = VISIBLE
|
||||
enableButton(true)
|
||||
postSub?.dispose()
|
||||
sub.dispose()
|
||||
})
|
||||
}
|
||||
|
||||
private fun post(id: String) {
|
||||
if (id.isEmpty()) return
|
||||
private fun post() {
|
||||
enableButton(false)
|
||||
pixelfedAPI.postStatus(
|
||||
authorization = "Bearer $accessToken",
|
||||
statusText = description,
|
||||
media_ids = listOf(id)
|
||||
media_ids = listOfIds
|
||||
).enqueue(object: Callback<Status> {
|
||||
override fun onFailure(call: Call<Status>, t: Throwable) {
|
||||
enableButton(true)
|
||||
Toast.makeText(applicationContext,getString(R.string.upload_post_failed),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
Log.e(TAG, t.message + call.request())
|
||||
|
@ -173,14 +190,80 @@ class PostCreationActivity : AppCompatActivity() {
|
|||
if (response.code() == 200) {
|
||||
Toast.makeText(applicationContext,getString(R.string.upload_post_success),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
startActivity(Intent(applicationContext, MainActivity::class.java))
|
||||
val intent = Intent(this@PostCreationActivity, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
startActivity(intent)
|
||||
} else {
|
||||
Toast.makeText(applicationContext,getString(R.string.upload_post_error),
|
||||
Toast.LENGTH_SHORT).show()
|
||||
Log.e(TAG, call.request().toString() + response.raw().toString())
|
||||
enableButton(true)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
private fun enableButton(enable: Boolean = true){
|
||||
post_creation_send_button.isEnabled = enable
|
||||
if(enable){
|
||||
posting_progress_bar.visibility = GONE
|
||||
post_creation_send_button.visibility = VISIBLE
|
||||
} else{
|
||||
posting_progress_bar.visibility = VISIBLE
|
||||
post_creation_send_button.visibility = GONE
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ProgressRequestBody(private val mFile: File) : RequestBody() {
|
||||
|
||||
private val getProgressSubject: PublishSubject<Float> = PublishSubject.create()
|
||||
|
||||
val progressSubject: Observable<Float>
|
||||
get() {
|
||||
return getProgressSubject
|
||||
}
|
||||
|
||||
|
||||
override fun contentType(): MediaType? {
|
||||
return "image/png".toMediaTypeOrNull()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun contentLength(): Long {
|
||||
return mFile.length()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun writeTo(sink: BufferedSink) {
|
||||
val fileLength = contentLength()
|
||||
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||
val `in` = FileInputStream(mFile)
|
||||
var uploaded: Long = 0
|
||||
|
||||
`in`.use {
|
||||
var read: Int
|
||||
var lastProgressPercentUpdate = 0.0f
|
||||
read = it.read(buffer)
|
||||
while (read != -1) {
|
||||
|
||||
uploaded += read.toLong()
|
||||
sink.write(buffer, 0, read)
|
||||
read = it.read(buffer)
|
||||
|
||||
val progress = (uploaded.toFloat() / fileLength.toFloat()) * 100f
|
||||
//prevent publishing too many updates, which slows upload, by checking if the upload has progressed by at least 1 percent
|
||||
if (progress - lastProgressPercentUpdate > 1 || progress == 100f) {
|
||||
// publish progress
|
||||
getProgressSubject.onNext(progress)
|
||||
lastProgressPercentUpdate = progress
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_BUFFER_SIZE = 2048
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.h.pixeldroid.api
|
||||
|
||||
import com.h.pixeldroid.objects.*
|
||||
import io.reactivex.Observable
|
||||
import okhttp3.MultipartBody
|
||||
import retrofit2.Call
|
||||
import retrofit2.Retrofit
|
||||
|
@ -9,6 +10,7 @@ import retrofit2.converter.gson.GsonConverterFactory
|
|||
import retrofit2.http.*
|
||||
import retrofit2.http.Field
|
||||
|
||||
|
||||
/*
|
||||
Implements the Pixelfed API
|
||||
https://docs.pixelfed.org/technical-documentation/api-v1.html
|
||||
|
@ -233,7 +235,7 @@ interface PixelfedAPI {
|
|||
//The authorization header needs to be of the form "Bearer <token>"
|
||||
@Header("Authorization") authorization: String,
|
||||
@Part file: MultipartBody.Part
|
||||
): Call<Attachment>
|
||||
): Observable<Attachment>
|
||||
|
||||
// get instance configuration
|
||||
@GET("/api/v1/instance")
|
||||
|
@ -245,4 +247,3 @@ interface PixelfedAPI {
|
|||
@Header("Authorization") authorization: String
|
||||
) : Call<DiscoverPosts>
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ class ThemeUtils {
|
|||
fun setThemeFromPreferences(preferences: SharedPreferences, resources : Resources) {
|
||||
val themes = resources.getStringArray(R.array.theme_values)
|
||||
val theme = preferences.getString("theme", "")
|
||||
Log.e("themePref", theme!!)
|
||||
//Set the theme
|
||||
when(theme) {
|
||||
//Light
|
||||
|
|
|
@ -1,56 +1,140 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/upload_error"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:elevation="2dp"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.mikepenz.iconics.view.IconicsTextView
|
||||
android:id="@+id/upload_error_text_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#90000000"
|
||||
android:text="@string/media_upload_failed"
|
||||
android:textColor="@color/colorPrimaryError"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/retry_upload_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/retry"
|
||||
app:layout_constraintEnd_toEndOf="@id/upload_error_text_view"
|
||||
app:layout_constraintStart_toStartOf="@id/upload_error_text_view"
|
||||
app:layout_constraintTop_toBottomOf="@id/upload_error_text_view" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/post_creation_picture_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:contentDescription="TODO" />
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:contentDescription="@string/posting_image_accessibility_hint"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/buttonConstraints"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="#88000000">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/description"
|
||||
app:errorEnabled="true"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:paddingStart="15dp"
|
||||
android:textColorHint="@color/colorPrimaryTab"
|
||||
app:errorTextColor="@color/colorPrimaryError">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/new_post_description_input_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:ems="10"
|
||||
android:inputType="textMultiLine"
|
||||
android:textColor="@color/colorPrimary"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/textInputLayout2">
|
||||
|
||||
<Button
|
||||
android:id="@+id/post_creation_send_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:backgroundTint="@color/colorButtonBg"
|
||||
android:enabled="false"
|
||||
android:visibility="gone"
|
||||
android:text="@string/send"
|
||||
android:textColor="@color/colorButtonText"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/posting_progress_bar"
|
||||
style="?android:attr/progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/send"
|
||||
android:backgroundTint="@color/colorButtonBg"
|
||||
android:textColor="@color/colorButtonText"
|
||||
android:layout_margin="15dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
tools:ignore="PrivateResource"/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
||||
|
||||
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/uploadProgressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/textInputLayout2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/textInputLayout2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/description"
|
||||
android:paddingStart="15dp"
|
||||
android:paddingEnd="15dp"
|
||||
android:textColorHint="@color/colorPrimaryTab"
|
||||
app:errorEnabled="true"
|
||||
app:errorTextColor="@color/colorPrimaryError"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/buttonConstraints"
|
||||
app:layout_constraintStart_toStartOf="parent">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/new_post_description_input_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:ems="10"
|
||||
android:inputType="textMultiLine"
|
||||
android:textColor="@color/colorPrimary" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.mikepenz.iconics.view.IconicsTextView
|
||||
android:id="@+id/upload_completed_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/media_upload_completed"
|
||||
android:textColor="@android:color/holo_green_light"
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -35,7 +35,6 @@
|
|||
<string name="domain_of_your_instance">اسم نطاق مثيل خادمك</string>
|
||||
<string name="login_connection_required_once">يجب أن تكون متصلا بالأنترنت لتتمكن مِن إضافة أول حساب واستخدام PixelDroid :(</string>
|
||||
<string name="capture_button_alt">لقطة شاشة</string>
|
||||
<string name="you_are_in_offline_mode">إنك غير متصل الآن ولكنه لا يزال بإمكانك عرض بعض المحتوى!</string>
|
||||
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / وسائط مخفية
|
||||
\n (اضعط للعرض)</string>
|
||||
<string name="lbl_contrast">تباين عالٍ</string>
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
<string name="CommentDisplay">mostrar…</string>
|
||||
<string name="domain_of_your_instance">Domini de la teva instància</string>
|
||||
<string name="connect_to_pixelfed">Connecta’t a Pixelfed</string>
|
||||
<string name="you_are_in_offline_mode">Estàs en mode fora de línia, però encara pots veure algun contingut!</string>
|
||||
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Imatges ocultes
|
||||
\n(fes clic per mostrar)</string>
|
||||
<string name="add_account_description">Afegeix un altre compte</string>
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
<string name="domain_of_your_instance">Domain Ihrer Instanz</string>
|
||||
<string name="connect_to_pixelfed">Mit Pixelfed verbinden</string>
|
||||
<string name="login_connection_required_once">Sie müssen online sein, um das erste Konto hinzuzufügen und um PixelDroid verwenden zu können :(</string>
|
||||
<string name="you_are_in_offline_mode">Sie befinden sich im Offline-Modus, aber Sie können immer noch einige Inhalte ansehen!</string>
|
||||
<string name="switch_camera_button_alt">Kamera wechseln</string>
|
||||
<string name="registration_failed">Konnte die App nicht mit diesem Server verbinden</string>
|
||||
<string name="instance_error">Konnte die Informationen der Instanz nicht abrufen</string>
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
<string name="CommentDisplay">para mostrar…</string>
|
||||
<string name="domain_of_your_instance">Dominio de tu nodo</string>
|
||||
<string name="connect_to_pixelfed">Conectar con Pixelfed</string>
|
||||
<string name="you_are_in_offline_mode">Estás en modo sin conexión, ¡pero todavía puedes ver algo de contenido!</string>
|
||||
<string name="login_connection_required_once">Necesitas estar conectado para poder añadir la primera cuenta y utilizar PixelDroid :(</string>
|
||||
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Contenido Oculto
|
||||
\n (haz clic para mostrar)</string>
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
<string name="app_name">PixelDroid</string>
|
||||
<string name="gallery_button_alt">Galeria</string>
|
||||
<string name="NoCommentsToShow">Iruzkinik gabeko argitalpena…</string>
|
||||
<string name="you_are_in_offline_mode">Lineaz kanpo editatzeko moduan zaude, baina hala ere eduki batzuk ikus ditzakezu!</string>
|
||||
<string name="theme_title">Aplikazioaren gaia</string>
|
||||
<string name="tab_edit">EDITATU</string>
|
||||
<string name="switch_camera_button_alt">Aldatu kamera</string>
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
<string name="CommentDisplay">برای نمایش…</string>
|
||||
<string name="domain_of_your_instance">دامنهٔ نمونهٔ شما</string>
|
||||
<string name="connect_to_pixelfed">اتصال به پیکسلفد</string>
|
||||
<string name="you_are_in_offline_mode">شما در حالت برخط نیستید، اما همچنان میتوانید برخی محتواها را ببینید!</string>
|
||||
<string name="app_name">پیکسلدروید</string>
|
||||
<string name="menu_account">نمایهٔ من</string>
|
||||
<string name="registration_failed">نتوانستیم برنامه را روی این کارساز ثبت کنیم</string>
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
<string name="gallery_button_alt">Galerie</string>
|
||||
<string name="NoCommentsToShow">Aucun commentaire dans cette publication…</string>
|
||||
<string name="domain_of_your_instance">Domaine de votre instance</string>
|
||||
<string name="you_are_in_offline_mode">Vous êtes en mode hors ligne mais vous pouvez continuer accéder à un certain contenu !</string>
|
||||
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Média caché
|
||||
\n (appuyez pour afficher)</string>
|
||||
<string name="CommentDisplay">pour afficher…</string>
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
<string name="domain_of_your_instance">Dominio da túa instancia</string>
|
||||
<string name="connect_to_pixelfed">Conectar con Pixelfed</string>
|
||||
<string name="login_connection_required_once">Debes ter conexión a internet para poder engadir a conta e usar PixelDroid :(</string>
|
||||
<string name="you_are_in_offline_mode">Non tes conexión, pero aínda así podes ver algún contido!</string>
|
||||
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Agochado
|
||||
\n(preme para amosar)</string>
|
||||
<string name="app_name">PixelDroid</string>
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
<string name="gallery_button_alt">Galleria</string>
|
||||
<string name="domain_of_your_instance">Dominio della tua istanza</string>
|
||||
<string name="login_connection_required_once">È necessario connettersi a Internet almeno una volta per utilizzare PixelDroid :(</string>
|
||||
<string name="you_are_in_offline_mode">Sei in modalità offline, ma puoi comunque visualizzare alcuni contenuti!</string>
|
||||
<string name="invalid_domain">Dominio non valido</string>
|
||||
<string name="tab_edit">MODIFICA</string>
|
||||
</resources>
|
|
@ -39,7 +39,6 @@
|
|||
<string name="tab_edit">編集</string>
|
||||
<string name="image_download_failed">ダウンロードに失敗しました、もう一度実行してください</string>
|
||||
<string name="NoCommentsToShow">この投稿にはコメントがありません…</string>
|
||||
<string name="you_are_in_offline_mode">オフラインモードです、一部のコンテンツは引き続き表示できます</string>
|
||||
<string name="add_account_description">他のPixelfedアカウントを追加</string>
|
||||
<string name="add_account_name">アカウントを追加</string>
|
||||
<string name="instance_error">インスタンス情報が取得できませんでした</string>
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
<string name="domain_of_your_instance">Domein van je instance</string>
|
||||
<string name="connect_to_pixelfed">Met Pixelfed verbinden</string>
|
||||
<string name="login_connection_required_once">Je moet met het internet verbonden zijn om je eerste account toe te voegen en PixelDroid te kunnen gebruiken :(</string>
|
||||
<string name="you_are_in_offline_mode">Je bent in de offline modus, maar je kan nog steeds bepaalde inhoud zien!</string>
|
||||
<string name="add_account_description">Andere Pixelfed account toevoegen</string>
|
||||
<string name="add_account_name">Account toevoegen</string>
|
||||
</resources>
|
|
@ -12,7 +12,6 @@
|
|||
<string name="invalid_domain">Domínio inválido</string>
|
||||
<string name="add_account_description">Adicionar outra conta Pixelfed</string>
|
||||
<string name="add_account_name">Adicionar Conta</string>
|
||||
<string name="you_are_in_offline_mode">Você está em modo offline, mas ainda pode ver alguns conteúdos!</string>
|
||||
<string name="login_connection_required_once">Você precisa estar conectado para poder adicionar a primeira conta e usar o PixelDroid :(</string>
|
||||
<string name="connect_to_pixelfed">Conectar-se à Pixelfed</string>
|
||||
<string name="domain_of_your_instance">Domínio da sua instância</string>
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
<string name="image_download_failed">Скачивание не удалось, попробуйте ещё раз</string>
|
||||
<string name="share_picture">Поделиться изображение…</string>
|
||||
<string name="login_connection_required_once">Вам необходимо быть в сети что бы добавить аккаунт и использовать PixelDroid :(</string>
|
||||
<string name="you_are_in_offline_mode">Вы в оффлайн режиме, но вы можете видеть некоторый контент!</string>
|
||||
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Скрытое медиа
|
||||
\n (кликните что бы показать)</string>
|
||||
<string name="registration_failed">Не удалось зарегистрировать приложение на этом инстансе</string>
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
<string name="NoCommentsToShow">Inga kommentarer på detta inlägg…</string>
|
||||
<string name="CommentDisplay">att visa…</string>
|
||||
<string name="connect_to_pixelfed">Anslut till Pixelfed</string>
|
||||
<string name="you_are_in_offline_mode">Du är i nedkopplad läge, men du kan ändå se lite innehåll!</string>
|
||||
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Dold media
|
||||
\n(Tryck för att visa)</string>
|
||||
<string name="add_account_description">Lägg till ett annat Pixelfed-konto</string>
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
<string name="NoCommentsToShow">这条帖文下没有评论……</string>
|
||||
<string name="CommentDisplay">显示……</string>
|
||||
<string name="domain_of_your_instance">实例的域名</string>
|
||||
<string name="you_are_in_offline_mode">您处于离线模式,但仍可以查看已缓存内容!</string>
|
||||
<string name="connect_to_pixelfed">连接至 Pixelfed</string>
|
||||
<string name="share_picture">分享图片……</string>
|
||||
<string name="login_connection_required_once">您需要联网才能添加第一个帐户并使用 PixelDroid :(</string>
|
||||
|
|
|
@ -102,6 +102,12 @@
|
|||
<!-- Sensitive media -->
|
||||
<string name="cw_nsfw_hidden_media_n_click_to_show">CW / NSFW / Hidden Media \n (click to show)</string>
|
||||
|
||||
<!-- Shown when image has finished uploading. {gmd_cloud_done} is an icon, position it as is appropriate in target language -->
|
||||
<string name="media_upload_completed">{gmd_cloud_done} Media upload completed</string>
|
||||
<!-- Shown when image uploading has failed. {gmd_cloud_off} is an icon, position it as is appropriate in target language -->
|
||||
<string name="media_upload_failed">{gmd_cloud_off} Media upload failed, try again or check network conditions</string>
|
||||
|
||||
<string name="posting_image_accessibility_hint">Image being posted</string>
|
||||
<string name="retry">Retry</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in New Issue