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