From 50dd0bad5181ae8a864e5bfe4c2a429a5f2585fd Mon Sep 17 00:00:00 2001
From: Matthieu <24-artectrex@users.noreply.shinice.net>
Date: Sun, 4 Oct 2020 23:27:06 +0200
Subject: [PATCH] Add reporting and link sharing functionality, polish UI
---
app/build.gradle | 14 +-
app/src/main/AndroidManifest.xml | 35 +-
.../java/com/h/pixeldroid/CameraActivity.kt | 28 ++
.../java/com/h/pixeldroid/MainActivity.kt | 2 +-
.../com/h/pixeldroid/PhotoEditActivity.kt | 33 +-
.../main/java/com/h/pixeldroid/Pixeldroid.kt | 5 +-
.../com/h/pixeldroid/PostCreationActivity.kt | 130 +++++--
.../java/com/h/pixeldroid/ReportActivity.kt | 81 ++++
.../java/com/h/pixeldroid/SearchActivity.kt | 13 +-
.../java/com/h/pixeldroid/SettingsActivity.kt | 7 -
.../java/com/h/pixeldroid/api/PixelfedAPI.kt | 11 +
.../h/pixeldroid/di/ApplicationComponent.kt | 1 +
.../h/pixeldroid/fragments/CameraFragment.kt | 56 ++-
.../fragments/FilterListFragment.kt | 15 +-
.../h/pixeldroid/fragments/ImageFragment.kt | 62 +--
.../h/pixeldroid/fragments/PostFragment.kt | 26 +-
.../fragments/SearchDiscoverFragment.kt | 38 +-
.../fragments/feeds/AccountListFragment.kt | 8 +-
.../fragments/feeds/FeedFragment.kt | 2 +-
.../fragments/feeds/OfflineFeedFragment.kt | 4 +-
.../feeds/postFeeds/PostsFeedFragment.kt | 27 +-
.../java/com/h/pixeldroid/objects/Report.kt | 7 +
.../java/com/h/pixeldroid/objects/Status.kt | 362 ++++++++++++------
.../java/com/h/pixeldroid/utils/ImageUtils.kt | 99 -----
.../add_photo_alternate_black_24dp.xml | 9 +
.../add_photo_alternate_black_24dp.xml | 9 +
.../main/res/drawable/circle_black_24dp.xml | 9 +
app/src/main/res/drawable/lens_black_24dp.xml | 9 +
.../main/res/layout/account_list_entry.xml | 27 +-
app/src/main/res/layout/activity_camera.xml | 14 +
app/src/main/res/layout/activity_main.xml | 31 +-
.../main/res/layout/activity_photo_edit.xml | 12 +-
app/src/main/res/layout/activity_post.xml | 24 +-
.../res/layout/activity_post_creation.xml | 42 +-
app/src/main/res/layout/activity_profile.xml | 5 +-
app/src/main/res/layout/activity_report.xml | 69 ++++
.../res/layout/add_more_album_creation.xml | 15 +
app/src/main/res/layout/fragment_image.xml | 2 +-
.../res/layout/fragment_profile_posts.xml | 34 +-
app/src/main/res/layout/fragment_search.xml | 66 ++--
.../main/res/layout/image_album_creation.xml | 21 +-
app/src/main/res/layout/post_fragment.xml | 65 ++--
.../main/res/layout/thumbnail_list_item.xml | 13 +-
app/src/main/res/menu/image_popup_menu.xml | 7 -
app/src/main/res/menu/post_more_menu.xml | 17 +
app/src/main/res/values-ar/strings.xml | 2 +-
app/src/main/res/values-ca/strings.xml | 2 +-
app/src/main/res/values-de/strings.xml | 2 +-
app/src/main/res/values-es/strings.xml | 2 +-
app/src/main/res/values-eu/strings.xml | 2 +-
app/src/main/res/values-fa/strings.xml | 2 +-
app/src/main/res/values-fr/strings.xml | 2 +-
app/src/main/res/values-gl/strings.xml | 2 +-
app/src/main/res/values-it/strings.xml | 2 +-
app/src/main/res/values-ja/strings.xml | 2 +-
app/src/main/res/values-nl/strings.xml | 2 +-
app/src/main/res/values-pt-rBR/strings.xml | 2 +-
app/src/main/res/values-ru/strings.xml | 2 +-
app/src/main/res/values-sv/strings.xml | 2 +-
app/src/main/res/values-uk/strings.xml | 2 +-
app/src/main/res/values-zh-rCN/strings.xml | 2 +-
app/src/main/res/values/strings.xml | 18 +-
app/src/main/res/values/styles.xml | 1 -
app/src/main/res/xml/root_preferences.xml | 8 +-
app/src/main/res/xml/searchable.xml | 2 +-
65 files changed, 1021 insertions(+), 606 deletions(-)
create mode 100644 app/src/main/java/com/h/pixeldroid/CameraActivity.kt
create mode 100644 app/src/main/java/com/h/pixeldroid/ReportActivity.kt
create mode 100644 app/src/main/java/com/h/pixeldroid/objects/Report.kt
delete mode 100644 app/src/main/java/com/h/pixeldroid/utils/ImageUtils.kt
create mode 100644 app/src/main/res/drawable-night/add_photo_alternate_black_24dp.xml
create mode 100644 app/src/main/res/drawable/add_photo_alternate_black_24dp.xml
create mode 100644 app/src/main/res/drawable/circle_black_24dp.xml
create mode 100644 app/src/main/res/drawable/lens_black_24dp.xml
create mode 100644 app/src/main/res/layout/activity_camera.xml
create mode 100644 app/src/main/res/layout/activity_report.xml
create mode 100644 app/src/main/res/layout/add_more_album_creation.xml
delete mode 100644 app/src/main/res/menu/image_popup_menu.xml
create mode 100644 app/src/main/res/menu/post_more_menu.xml
diff --git a/app/build.gradle b/app/build.gradle
index 5126d24c..d356f708 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -65,7 +65,7 @@ dependencies {
* AndroidX dependencies:
*/
implementation 'androidx.appcompat:appcompat:1.2.0'
- implementation 'androidx.core:core-ktx:1.3.1'
+ implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.navigation:navigation-fragment:2.3.0'
@@ -80,6 +80,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-savedstate:2.2.0'
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0"
implementation "androidx.annotation:annotation:1.1.0"
+ implementation 'androidx.gridlayout:gridlayout:1.0.0'
// Use the most recent version of CameraX
def camerax_version = '1.0.0-beta08'
@@ -104,8 +105,6 @@ dependencies {
implementation 'com.google.android.material:material:1.2.1'
- implementation 'com.google.android:flexbox:2.0.1'
-
//Dagger (dependency injection)
implementation 'com.google.dagger:dagger-android:2.28.3'
implementation 'com.google.dagger:dagger-android-support:2.28.3'
@@ -138,13 +137,14 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
- implementation "com.mikepenz:materialdrawer:8.1.4"
+ implementation "com.mikepenz:materialdrawer:8.1.5"
// Add for NavController support
- implementation "com.mikepenz:materialdrawer-nav:8.0.3"
+ implementation "com.mikepenz:materialdrawer-nav:8.1.5"
//iconics
- implementation "com.mikepenz:materialdrawer-iconics:8.1.4"
- implementation "com.mikepenz:iconics-views:5.0.2"
+ implementation "com.mikepenz:iconics-core:5.0.3"
+ implementation "com.mikepenz:materialdrawer-iconics:8.1.5"
+ implementation "com.mikepenz:iconics-views:5.0.3"
implementation 'com.mikepenz:google-material-typeface:3.0.1.4.original-kotlin@aar'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d7d79c03..423a9543 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -24,9 +24,12 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:replace="android:allowBackup">
+
+ android:name=".ReportActivity"
+ android:screenOrientation="sensorPortrait"
+ tools:ignore="LockedOrientationActivity" />
+
+ tools:ignore="LockedOrientationActivity" />
+
+
-
+
-
-
-
+
-
+ tools:ignore="LockedOrientationActivity" />
- if(uri == null) {
- Log.e("NEW IMAGE SCAN FAILED", "Tried to scan $path, but it failed")
+ ) { path, uri ->
+ if (uri == null) {
+ Log.e(
+ "NEW IMAGE SCAN FAILED",
+ "Tried to scan $path, but it failed"
+ )
+ }
}
}
diff --git a/app/src/main/java/com/h/pixeldroid/Pixeldroid.kt b/app/src/main/java/com/h/pixeldroid/Pixeldroid.kt
index 84d242e5..9b6ea30b 100644
--- a/app/src/main/java/com/h/pixeldroid/Pixeldroid.kt
+++ b/app/src/main/java/com/h/pixeldroid/Pixeldroid.kt
@@ -4,6 +4,7 @@ import android.app.Application
import androidx.preference.PreferenceManager
import com.h.pixeldroid.di.*
import com.h.pixeldroid.utils.ThemeUtils
+import com.mikepenz.iconics.Iconics
import org.ligi.tracedroid.TraceDroid
@@ -23,7 +24,9 @@ class Pixeldroid: Application() {
.databaseModule(DatabaseModule(applicationContext))
.aPIModule(APIModule())
.build()
- mApplicationComponent.inject(this);
+ mApplicationComponent.inject(this)
+
+ Iconics.init(applicationContext)
}
fun getAppComponent(): ApplicationComponent {
diff --git a/app/src/main/java/com/h/pixeldroid/PostCreationActivity.kt b/app/src/main/java/com/h/pixeldroid/PostCreationActivity.kt
index a699354d..1330babd 100644
--- a/app/src/main/java/com/h/pixeldroid/PostCreationActivity.kt
+++ b/app/src/main/java/com/h/pixeldroid/PostCreationActivity.kt
@@ -1,7 +1,6 @@
package com.h.pixeldroid
import android.app.Activity
-import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
@@ -26,7 +25,6 @@ import com.h.pixeldroid.interfaces.PostCreationListener
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 com.h.pixeldroid.utils.ProgressRequestBody
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
@@ -39,9 +37,11 @@ import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
-class PostCreationActivity : AppCompatActivity(), PostCreationListener {
+private val TAG = "Post Creation Activity"
+private val MORE_PICTURES_REQUEST_CODE = 0xffff
- private val TAG = "Post Creation Activity"
+
+class PostCreationActivity : AppCompatActivity(), PostCreationListener {
private lateinit var recycler : RecyclerView
private lateinit var adapter : PostCreationAdapter
@@ -74,16 +74,19 @@ class PostCreationActivity : AppCompatActivity(), PostCreationListener {
(this.application as Pixeldroid).getAppComponent().inject(this)
- // load images
- posts = intent.getStringArrayListExtra("pictures_uri")!!
-
- progressList = posts.map { 0 } as ArrayList
- muListOfIds = posts.map { "" }.toMutableList()
+ // get image URIs
+ if(intent.clipData != null) {
+ val count = intent.clipData!!.itemCount
+ for (i in 0 until count) {
+ val imageUri: String = intent.clipData!!.getItemAt(i).uri.toString()
+ posts.add(imageUri)
+ }
+ }
user = db.userDao().getActiveUser()
val instances = db.instanceDao().getAll()
- maxLength = if (user!=null){
+ maxLength = if (user != null){
val thisInstances =
instances.filter { instanceDatabaseEntity ->
instanceDatabaseEntity.uri.contains(user!!.instance_uri)
@@ -100,12 +103,14 @@ class PostCreationActivity : AppCompatActivity(), PostCreationListener {
// TODO
//upload the picture and display progress while doing so
+ muListOfIds = posts.map { "" }.toMutableList()
+ progressList = posts.map { 0 } as ArrayList
upload()
adapter = PostCreationAdapter(posts)
adapter.listener = this
recycler = findViewById(R.id.image_grid)
- recycler.layoutManager = GridLayoutManager(this, if (posts.size > 2) 2 else 1)
+ recycler.layoutManager = GridLayoutManager(this, 3)
recycler.adapter = adapter
// get the description and send the post
@@ -126,8 +131,8 @@ class PostCreationActivity : AppCompatActivity(), PostCreationListener {
val textField = findViewById(R.id.new_post_description_input_field)
val content = textField.text.toString()
if (content.length > maxLength) {
- // error, too much characters
- textField.error = "Description must contain $maxLength characters at most."
+ // error, too many characters
+ textField.error = getString(R.string.description_max_characters).format(maxLength)
return false
}
// store the description
@@ -135,9 +140,26 @@ class PostCreationActivity : AppCompatActivity(), PostCreationListener {
return true
}
- private fun upload() {
- for ((index, post) in posts.withIndex()) {
- val imageUri = Uri.parse(post)
+ /**
+ * Uploads the images that are in the [posts] array.
+ * Keeps track of them in the [progressList] (for the upload progress), and the [muListOfIds]
+ * (for the list of ids of the uploads).
+ * @param newImagesStartingIndex is the index in the [posts] array we want to start uploading at.
+ * Indices before this are already uploading, or done uploading, from before.
+ * @param editedImage contains the index of the image that was edited. If set, other images are
+ * not uploaded again: they should already be uploading, or be done uploading, from before.
+ */
+ private fun upload(newImagesStartingIndex: Int = 0, editedImage: Int? = null) {
+ enableButton(false)
+ uploadProgressBar.visibility = View.VISIBLE
+ upload_completed_textview.visibility = View.INVISIBLE
+
+ val range: IntRange = if(editedImage == null){
+ newImagesStartingIndex until posts.size
+ } else IntRange(editedImage, editedImage)
+
+ for (index in range) {
+ val imageUri = Uri.parse(posts[index])
val imageInputStream = contentResolver.openInputStream(imageUri)!!
val size =
@@ -237,7 +259,7 @@ class PostCreationActivity : AppCompatActivity(), PostCreationListener {
if(enable){
posting_progress_bar.visibility = View.GONE
post_creation_send_button.visibility = View.VISIBLE
- } else{
+ } else {
posting_progress_bar.visibility = View.VISIBLE
post_creation_send_button.visibility = View.GONE
}
@@ -259,51 +281,85 @@ class PostCreationActivity : AppCompatActivity(), PostCreationListener {
if (resultCode == Activity.RESULT_OK && data != null) {
posts[positionResult] = data.getStringExtra("result")!!
adapter.notifyItemChanged(positionResult)
- muListOfIds.clear()
- upload()
- }
- else if(resultCode == Activity.RESULT_CANCELED){
- Toast.makeText(applicationContext, "Edition cancelled", Toast.LENGTH_SHORT).show()
+ muListOfIds[positionResult] = ""
+ progressList[positionResult] = 0
+ upload(editedImage = positionResult)
+ } else if(resultCode == Activity.RESULT_CANCELED){
+ Toast.makeText(applicationContext, "Editing cancelled", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(applicationContext, "Error while editing", Toast.LENGTH_SHORT).show()
}
+ } else if (requestCode == MORE_PICTURES_REQUEST_CODE) {
+ if (resultCode == Activity.RESULT_OK && data?.clipData != null) {
+
+ val count = data.clipData!!.itemCount
+ for (i in 0 until count) {
+ val imageUri: String = data.clipData!!.getItemAt(i).uri.toString()
+ posts.add(imageUri)
+ progressList.add(0)
+ muListOfIds.add(i, "")
+ }
+ adapter.notifyDataSetChanged()
+ upload(newImagesStartingIndex = posts.size - count)
+ } else if(resultCode == Activity.RESULT_CANCELED){
+ Toast.makeText(applicationContext, "Adding images", Toast.LENGTH_SHORT).show()
+ } else {
+ Toast.makeText(applicationContext, "Error while adding images", Toast.LENGTH_SHORT).show()
+ }
}
}
- class PostCreationAdapter(private val posts: ArrayList): RecyclerView.Adapter() {
- private var context: Context? = null
+ inner class PostCreationAdapter(private val posts: ArrayList): RecyclerView.Adapter() {
var listener: PostCreationListener? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
- context = parent.context
- val view = LayoutInflater.from(parent.context)
+ val view =
+ if(viewType == 0) LayoutInflater.from(parent.context)
.inflate(R.layout.image_album_creation, parent, false)
+ else LayoutInflater.from(parent.context)
+ .inflate(R.layout.add_more_album_creation, parent, false)
return ViewHolder(view)
}
- override fun onBindViewHolder(holder: ViewHolder, position: Int) {
- Log.d("test", "binded")
- holder.bind()
+ override fun getItemViewType(position: Int): Int {
+ if(position == posts.size) return 1
+ return 0
}
- override fun getItemCount(): Int = posts.size
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ if(position != posts.size) {
+ holder.bindImage()
+ } else{
+ holder.bindPlusButton()
+ }
+ }
+
+ override fun getItemCount(): Int = posts.size + 1
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
- fun bind() {
- val image = Uri.parse(posts[adapterPosition])
+ fun bindImage() {
+ val image = Uri.parse(
+ posts[adapterPosition]
+ )
// load image
- Glide.with(context!!)
+ Glide.with(itemView.context)
.load(image)
.centerCrop()
.into(itemView.galleryImage)
-
// adding click or tap handler for the image layout
- itemView.galleryImage.setOnClickListener {
- Log.d("test", "clicked")
+ itemView.setOnClickListener {
listener?.onClick(adapterPosition)
}
+
+ }
+
+ fun bindPlusButton() {
+ itemView.setOnClickListener {
+ val intent = Intent(itemView.context, CameraActivity::class.java)
+ this@PostCreationActivity.startActivityForResult(intent, MORE_PICTURES_REQUEST_CODE)
+ }
}
}
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/h/pixeldroid/ReportActivity.kt b/app/src/main/java/com/h/pixeldroid/ReportActivity.kt
new file mode 100644
index 00000000..461e5a19
--- /dev/null
+++ b/app/src/main/java/com/h/pixeldroid/ReportActivity.kt
@@ -0,0 +1,81 @@
+package com.h.pixeldroid
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import android.util.Log
+import android.view.View
+import com.h.pixeldroid.db.AppDatabase
+import com.h.pixeldroid.di.PixelfedAPIHolder
+import com.h.pixeldroid.objects.Report
+import com.h.pixeldroid.objects.Status
+import kotlinx.android.synthetic.main.activity_report.*
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+import javax.inject.Inject
+
+class ReportActivity : AppCompatActivity() {
+
+ @Inject
+ lateinit var db: AppDatabase
+ @Inject
+ lateinit var apiHolder: PixelfedAPIHolder
+
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_report)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ supportActionBar?.setTitle(R.string.report)
+
+ val status = intent.getSerializableExtra(Status.POST_TAG) as Status?
+
+ (this.application as Pixeldroid).getAppComponent().inject(this)
+ //get the currently active user
+ val user = db.userDao().getActiveUser()
+
+
+ report_target_textview.text = getString(R.string.report_target).format(status?.account?.acct)
+
+
+ reportButton.setOnClickListener{
+ reportButton.visibility = View.INVISIBLE
+ reportProgressBar.visibility = View.VISIBLE
+
+ textInputLayout.editText?.isEnabled = false
+
+ val accessToken = user?.accessToken.orEmpty()
+ val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db)
+ api.report("Bearer $accessToken", status?.account?.id!!, listOf(status), textInputLayout.editText?.text.toString())
+ .enqueue(object : Callback {
+ override fun onResponse(
+ call: Call,
+ response: Response
+ ) {
+ if (response.body() == null || !response.isSuccessful) {
+ textInputLayout.error = getString(R.string.report_error)
+ reportButton.visibility = View.VISIBLE
+ textInputLayout.editText?.isEnabled = true
+ reportProgressBar.visibility = View.GONE
+ } else {
+ reportProgressBar.visibility = View.GONE
+ reportButton.isEnabled = false
+ reportButton.text = getString(R.string.reported)
+ reportButton.visibility = View.VISIBLE
+ }
+ }
+
+ override fun onFailure(call: Call, t: Throwable) {
+ Log.e("REPORT:", t.toString())
+ }
+ })
+
+ }
+ }
+
+
+ override fun onSupportNavigateUp(): Boolean {
+ onBackPressed()
+ return true
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/h/pixeldroid/SearchActivity.kt b/app/src/main/java/com/h/pixeldroid/SearchActivity.kt
index f9384499..ab332925 100644
--- a/app/src/main/java/com/h/pixeldroid/SearchActivity.kt
+++ b/app/src/main/java/com/h/pixeldroid/SearchActivity.kt
@@ -20,9 +20,15 @@ class SearchActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+
+ var query = ""
+ if (Intent.ACTION_SEARCH == intent.action) {
+ query = intent.getStringExtra(SearchManager.QUERY).orEmpty()
+ }
- var query = intent.getSerializableExtra("searchFeed") as String
query = query.trim()
+ supportActionBar?.title = query
val searchType = when {
query.startsWith("#") -> {
@@ -41,6 +47,11 @@ class SearchActivity : AppCompatActivity() {
setupTabs(tabs, searchType)
}
+ override fun onSupportNavigateUp(): Boolean {
+ onBackPressed()
+ return true
+ }
+
private fun createSearchTabs(query: String): Array{
val searchFeedFragment =
diff --git a/app/src/main/java/com/h/pixeldroid/SettingsActivity.kt b/app/src/main/java/com/h/pixeldroid/SettingsActivity.kt
index 285caaf7..03914ce8 100644
--- a/app/src/main/java/com/h/pixeldroid/SettingsActivity.kt
+++ b/app/src/main/java/com/h/pixeldroid/SettingsActivity.kt
@@ -54,13 +54,6 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
- val button: Preference? = findPreference("about")
- button?.onPreferenceClickListener =
- Preference.OnPreferenceClickListener {
- val intent = Intent(context, AboutActivity::class.java)
- startActivity(intent)
- true
- }
}
}
diff --git a/app/src/main/java/com/h/pixeldroid/api/PixelfedAPI.kt b/app/src/main/java/com/h/pixeldroid/api/PixelfedAPI.kt
index 151c13e1..e5d6c45a 100644
--- a/app/src/main/java/com/h/pixeldroid/api/PixelfedAPI.kt
+++ b/app/src/main/java/com/h/pixeldroid/api/PixelfedAPI.kt
@@ -266,4 +266,15 @@ interface PixelfedAPI {
fun discover(
@Header("Authorization") authorization: String
) : Call
+
+ @FormUrlEncoded
+ @POST("/api/v1/reports")
+ fun report(
+ @Header("Authorization") authorization: String,
+ @Field("account_id") account_id: String,
+ @Field("status_ids") status_ids: List,
+ @Field("comment") comment: String,
+ @Field("forward") forward: Boolean = true
+ ) : Call
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/h/pixeldroid/di/ApplicationComponent.kt b/app/src/main/java/com/h/pixeldroid/di/ApplicationComponent.kt
index 49ddb48c..71b2b731 100644
--- a/app/src/main/java/com/h/pixeldroid/di/ApplicationComponent.kt
+++ b/app/src/main/java/com/h/pixeldroid/di/ApplicationComponent.kt
@@ -24,6 +24,7 @@ interface ApplicationComponent {
fun inject(activity: PostCreationActivity?)
fun inject(activity: ProfileActivity?)
fun inject(mainActivity: MainActivity?)
+ fun inject(activity: ReportActivity?)
fun inject(fragment: PostFragment)
fun inject(fragment: SearchDiscoverFragment)
fun inject(fragment: OfflineFeedFragment)
diff --git a/app/src/main/java/com/h/pixeldroid/fragments/CameraFragment.kt b/app/src/main/java/com/h/pixeldroid/fragments/CameraFragment.kt
index a73a5fc5..ffcb80dd 100644
--- a/app/src/main/java/com/h/pixeldroid/fragments/CameraFragment.kt
+++ b/app/src/main/java/com/h/pixeldroid/fragments/CameraFragment.kt
@@ -2,6 +2,7 @@ package com.h.pixeldroid.fragments
import android.Manifest
import android.app.Activity
+import android.content.ClipData
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
@@ -23,13 +24,14 @@ import androidx.camera.view.PreviewView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
+import androidx.core.net.toUri
import androidx.core.view.setPadding
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
-import com.h.pixeldroid.PhotoEditActivity
import com.h.pixeldroid.PostCreationActivity
+import com.h.pixeldroid.CameraActivity
import com.h.pixeldroid.R
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -39,6 +41,7 @@ import java.util.concurrent.Executors
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
+import kotlin.properties.Delegates
// This is an arbitrary number we are using to keep track of the permission
// request. Where an app has multiple context for requesting permission,
@@ -54,7 +57,10 @@ class CameraFragment : Fragment() {
private lateinit var container: ConstraintLayout
private lateinit var viewFinder: PreviewView
- private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE)
+ private val REQUIRED_PERMISSIONS = arrayOf(
+ Manifest.permission.CAMERA,
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ )
private val PICK_IMAGE_REQUEST = 1
private val CAPTURE_IMAGE_REQUEST = 2
@@ -64,6 +70,8 @@ class CameraFragment : Fragment() {
private var imageCapture: ImageCapture? = null
private var camera: Camera? = null
+ private var inActivity by Delegates.notNull()
+
/** Blocking camera operations are performed using this executor */
private lateinit var cameraExecutor: ExecutorService
@@ -90,7 +98,8 @@ class CameraFragment : Fragment() {
*/
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
- requireContext(), it) == PackageManager.PERMISSION_GRANTED
+ requireContext(), it
+ ) == PackageManager.PERMISSION_GRANTED
}
override fun onDestroyView() {
@@ -105,8 +114,12 @@ class CameraFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?): View? =
- inflater.inflate(R.layout.fragment_camera, container, false)
+ savedInstanceState: Bundle?
+ ): View? {
+ inActivity = arguments?.getBoolean("CameraActivity") ?: false
+
+ return inflater.inflate(R.layout.fragment_camera, container, false)
+ }
private fun setGalleryThumbnail(uri: String) {
// Reference of the view that holds the gallery thumbnail
@@ -203,11 +216,12 @@ class CameraFragment : Fragment() {
// A variable number of use-cases can be passed here -
// camera provides access to CameraControl & CameraInfo
camera = cameraProvider.bindToLifecycle(
- this, cameraSelector, preview, imageCapture)
+ this, cameraSelector, preview, imageCapture
+ )
// Attach the viewfinder's surface provider to preview use case
preview?.setSurfaceProvider(viewFinder.createSurfaceProvider())
- } catch(exc: Exception) {
+ } catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
@@ -246,7 +260,6 @@ class CameraFragment : Fragment() {
// In the background, load latest photo taken (if any) for gallery thumbnail
lifecycleScope.launch(Dispatchers.IO) {
- // Find the last picture
// Find the last picture
val projection = arrayOf(
MediaStore.Images.ImageColumns._ID,
@@ -382,10 +395,29 @@ class CameraFragment : Fragment() {
}
private fun startAlbumCreation(uris: ArrayList) {
- startActivity(
- Intent(activity, PostCreationActivity::class.java)
- .putExtra("pictures_uri", uris)
- )
+
+ val intent = Intent(requireActivity(), PostCreationActivity::class.java)
+ .apply {
+ uris.forEach{
+ //Why are we using ClipData here? Because the FLAG_GRANT_READ_URI_PERMISSION
+ //needs to be applied to the URIs, and this flag flag only applies to the
+ //Intent's data and any URIs specified in its ClipData.
+ if(clipData == null){
+ clipData = ClipData("", emptyArray(), ClipData.Item(it.toUri()))
+ } else {
+ clipData!!.addItem(ClipData.Item(it.toUri()))
+ }
+ }
+ addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ }
+
+ if(inActivity){
+ requireActivity().setResult(Activity.RESULT_OK, intent)
+ requireActivity().finish()
+ } else {
+ startActivity(intent)
+ }
}
companion object {
diff --git a/app/src/main/java/com/h/pixeldroid/fragments/FilterListFragment.kt b/app/src/main/java/com/h/pixeldroid/fragments/FilterListFragment.kt
index 501ba613..9d687a98 100644
--- a/app/src/main/java/com/h/pixeldroid/fragments/FilterListFragment.kt
+++ b/app/src/main/java/com/h/pixeldroid/fragments/FilterListFragment.kt
@@ -50,11 +50,14 @@ class FilterListFragment : Fragment(), FilterListFragmentListener {
recyclerView.addItemDecoration(SpaceItemDecoration(space))
recyclerView.adapter = adapter
- displayImage(null)
-
return view
}
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+ displayImage(null)
+ }
+
private fun displayImage(bitmap: Bitmap?) {
val r = Runnable {
val tbImage: Bitmap = (if (bitmap == null) {
@@ -74,10 +77,10 @@ class FilterListFragment : Fragment(), FilterListFragmentListener {
})
?: return@Runnable
- setupFilter(tbImage)
+ if(activity != null) setupFilter(tbImage)
- tbItemList.addAll(ThumbnailsManager.processThumbs(activity))
- requireActivity().runOnUiThread{ adapter.notifyDataSetChanged() }
+ if(context != null) tbItemList.addAll(ThumbnailsManager.processThumbs(context))
+ activity?.runOnUiThread{ adapter.notifyDataSetChanged() }
}
Thread(r).start()
@@ -93,7 +96,7 @@ class FilterListFragment : Fragment(), FilterListFragmentListener {
tbItem.filterName = tbItem.filter.name
ThumbnailsManager.addThumb(tbItem)
- val filters = FilterPack.getFilterPack(requireActivity())
+ val filters = FilterPack.getFilterPack(context)
for (filter in filters) {
val item = ThumbnailItem()
diff --git a/app/src/main/java/com/h/pixeldroid/fragments/ImageFragment.kt b/app/src/main/java/com/h/pixeldroid/fragments/ImageFragment.kt
index 8456ef1c..e41932c0 100644
--- a/app/src/main/java/com/h/pixeldroid/fragments/ImageFragment.kt
+++ b/app/src/main/java/com/h/pixeldroid/fragments/ImageFragment.kt
@@ -1,6 +1,5 @@
package com.h.pixeldroid.fragments
-import android.Manifest
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
@@ -9,18 +8,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
-import android.widget.PopupMenu
-import android.widget.Toast
import com.bumptech.glide.Glide
+import com.google.android.material.snackbar.Snackbar
import com.h.pixeldroid.R
-import com.h.pixeldroid.utils.ImageUtils
-import com.karumi.dexter.Dexter
-import com.karumi.dexter.listener.PermissionDeniedResponse
-import com.karumi.dexter.listener.PermissionGrantedResponse
-import com.karumi.dexter.listener.single.BasePermissionListener
+import kotlinx.android.synthetic.main.fragment_image.*
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val IMG_URL = "imgurl"
+private const val IMG_DESCRIPTION = "imgdescription"
private const val RQST_BLDR = "rqstbldr"
/**
@@ -30,11 +25,13 @@ private const val RQST_BLDR = "rqstbldr"
*/
class ImageFragment : Fragment() {
private lateinit var imgUrl: String
+ private lateinit var imgDescription: String
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
- imgUrl = it.getString(IMG_URL)!!
+ imgUrl = it.getString(IMG_URL)!!
+ imgDescription = it.getString(IMG_DESCRIPTION)!!.ifEmpty { getString(R.string.no_description) }
}
}
@@ -45,49 +42,10 @@ class ImageFragment : Fragment() {
val view = inflater.inflate(R.layout.fragment_image, container, false)
view.findViewById(R.id.imageImageView).setOnLongClickListener {
- PopupMenu(view.context, it).apply {
- setOnMenuItemClickListener { item ->
- when (item.itemId) {
- R.id.image_popup_menu_save_to_gallery -> {
- Dexter.withContext(view.context)
- .withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .withListener(object: BasePermissionListener() {
- override fun onPermissionDenied(p0: PermissionDeniedResponse?) {
- Toast.makeText(view.context,
- view.context.getString(R.string.write_permission_download_pic),
- Toast.LENGTH_SHORT).show()
- }
-
- override fun onPermissionGranted(p0: PermissionGrantedResponse?) {
- ImageUtils.downloadImage(requireActivity(), imgUrl)
- }
- }).check()
- true
- }
- R.id.image_popup_menu_share_picture -> {
- Dexter.withContext(view.context)
- .withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .withListener(object: BasePermissionListener() {
- override fun onPermissionDenied(p0: PermissionDeniedResponse?) {
- Toast.makeText(view.context,
- view.context.getString(R.string.write_permission_share_pic),
- Toast.LENGTH_SHORT).show()
- }
-
- override fun onPermissionGranted(p0: PermissionGrantedResponse?) {
- ImageUtils.downloadImage(requireActivity(), imgUrl, share = true)
- }
- }).check()
- true
- }
- else -> false
- }
- }
- inflate(R.menu.image_popup_menu)
- show()
- }
+ Snackbar.make(it, imgDescription, Snackbar.LENGTH_SHORT).show()
true
}
+
// Inflate the layout for this fragment
return view
}
@@ -100,6 +58,7 @@ class ImageFragment : Fragment() {
.placeholder(ColorDrawable(Color.GRAY))
.load(imgUrl)
.into(view.findViewById(R.id.imageImageView)!!)
+ imageImageView.contentDescription = imgDescription
}
companion object {
@@ -111,10 +70,11 @@ class ImageFragment : Fragment() {
* @return A new instance of fragment ImageFragment.
*/
@JvmStatic
- fun newInstance(imageUrl: String) =
+ fun newInstance(imageUrl: String, imageDescription: String) =
ImageFragment().apply {
arguments = Bundle().apply {
putString(IMG_URL, imageUrl)
+ putString(IMG_DESCRIPTION, imageDescription)
}
}
}
diff --git a/app/src/main/java/com/h/pixeldroid/fragments/PostFragment.kt b/app/src/main/java/com/h/pixeldroid/fragments/PostFragment.kt
index b66efdab..422e656a 100644
--- a/app/src/main/java/com/h/pixeldroid/fragments/PostFragment.kt
+++ b/app/src/main/java/com/h/pixeldroid/fragments/PostFragment.kt
@@ -39,14 +39,6 @@ class PostFragment : Fragment() {
.asDrawable().fitCenter()
.placeholder(ColorDrawable(Color.GRAY))
- currentStatus?.setupPost(root, picRequest, this, statusDomain, true)
-
- //Setup arguments needed for the onclicklisteners
- val holder = PostViewHolder(
- root,
- requireContext()
- )
-
(requireActivity().application as Pixeldroid).getAppComponent().inject(this)
val user = db.userDao().getActiveUser()
@@ -54,21 +46,17 @@ class PostFragment : Fragment() {
val accessToken = user?.accessToken.orEmpty()
val api = apiHolder.api ?: apiHolder.setDomainToCurrentUser(db)
- currentStatus?.setDescription(root, api, "Bearer $accessToken")
+ currentStatus?.setupPost(root, picRequest, this, statusDomain, true)
- //Activate onclickListeners
- currentStatus?.activateLiker(holder, api, "Bearer $accessToken",
- currentStatus.favourited ?: false
+ val holder = PostViewHolder(
+ root,
+ root.context
)
- currentStatus?.activateReblogger(holder, api, "Bearer $accessToken",
- currentStatus.reblogged ?: false
- )
- currentStatus?.activateCommenter(holder, api, "Bearer $accessToken")
- currentStatus?.showComments(holder, api, "Bearer $accessToken")
- //Activate double tap liking
- currentStatus?.activateDoubleTapLiker(holder, api, "Bearer $accessToken")
+ currentStatus?.activateButtons(holder, api, "Bearer $accessToken")
+
return root
+
}
}
diff --git a/app/src/main/java/com/h/pixeldroid/fragments/SearchDiscoverFragment.kt b/app/src/main/java/com/h/pixeldroid/fragments/SearchDiscoverFragment.kt
index 5fab7fec..d3e0d12b 100644
--- a/app/src/main/java/com/h/pixeldroid/fragments/SearchDiscoverFragment.kt
+++ b/app/src/main/java/com/h/pixeldroid/fragments/SearchDiscoverFragment.kt
@@ -1,19 +1,21 @@
package com.h.pixeldroid.fragments
+import android.app.SearchManager
+import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.Button
-import android.widget.EditText
-import android.widget.ImageView
-import android.widget.ProgressBar
+import android.widget.*
+import androidx.appcompat.widget.SearchView
+import androidx.core.content.ContextCompat.getSystemService
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
+import com.google.android.material.textview.MaterialTextView
import com.h.pixeldroid.Pixeldroid
import com.h.pixeldroid.PostActivity
import com.h.pixeldroid.R
@@ -26,6 +28,12 @@ import com.h.pixeldroid.objects.DiscoverPosts
import com.h.pixeldroid.objects.Status
import com.h.pixeldroid.utils.DBUtils
import com.h.pixeldroid.utils.ImageConverter
+import com.mikepenz.iconics.IconicsDrawable
+import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
+import com.mikepenz.iconics.utils.padding
+import com.mikepenz.iconics.utils.paddingDp
+import com.mikepenz.iconics.utils.sizeDp
+import kotlinx.android.synthetic.main.fragment_search.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
@@ -55,22 +63,30 @@ class SearchDiscoverFragment : Fragment() {
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_search, container, false)
- val button = view.findViewById