mirror of
				https://github.com/SimpleMobileTools/Simple-Camera.git
				synced 2025-06-27 09:02:59 +02:00 
			
		
		
		
	misc tweaks here and there
This commit is contained in:
		| @@ -1,10 +1,8 @@ | |||||||
| package com.simplemobiletools.camera | package com.simplemobiletools.camera | ||||||
|  |  | ||||||
| object Constants { | val ORIENT_PORTRAIT = 0 | ||||||
|     val ORIENT_PORTRAIT = 0 | val ORIENT_LANDSCAPE_LEFT = 1 | ||||||
|     val ORIENT_LANDSCAPE_LEFT = 1 | val ORIENT_LANDSCAPE_RIGHT = 2 | ||||||
|     val ORIENT_LANDSCAPE_RIGHT = 2 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // shared preferences | // shared preferences | ||||||
| val SAVE_PHOTOS = "save_photos" | val SAVE_PHOTOS = "save_photos" | ||||||
|   | |||||||
| @@ -4,12 +4,16 @@ import android.net.Uri | |||||||
| import android.os.AsyncTask | import android.os.AsyncTask | ||||||
| import android.os.Environment | import android.os.Environment | ||||||
| import android.util.Log | import android.util.Log | ||||||
|  | import com.simplemobiletools.camera.Preview.Companion.config | ||||||
| import com.simplemobiletools.camera.activities.MainActivity | import com.simplemobiletools.camera.activities.MainActivity | ||||||
| import com.simplemobiletools.camera.extensions.getOutputMediaFile | import com.simplemobiletools.camera.extensions.getOutputMediaFile | ||||||
| import com.simplemobiletools.commons.extensions.getFileDocument | import com.simplemobiletools.commons.extensions.getFileDocument | ||||||
| import com.simplemobiletools.commons.extensions.needsStupidWritePermissions | import com.simplemobiletools.commons.extensions.needsStupidWritePermissions | ||||||
| import com.simplemobiletools.commons.extensions.toast | import com.simplemobiletools.commons.extensions.toast | ||||||
| import java.io.* | import java.io.File | ||||||
|  | import java.io.FileOutputStream | ||||||
|  | import java.io.IOException | ||||||
|  | import java.io.OutputStream | ||||||
| import java.lang.ref.WeakReference | import java.lang.ref.WeakReference | ||||||
|  |  | ||||||
| class PhotoProcessor(val activity: MainActivity, val uri: Uri?) : AsyncTask<ByteArray, Void, String>() { | class PhotoProcessor(val activity: MainActivity, val uri: Uri?) : AsyncTask<ByteArray, Void, String>() { | ||||||
| @@ -38,7 +42,6 @@ class PhotoProcessor(val activity: MainActivity, val uri: Uri?) : AsyncTask<Byte | |||||||
|  |  | ||||||
|             val photoFile = File(path) |             val photoFile = File(path) | ||||||
|             if (activity.needsStupidWritePermissions(path)) { |             if (activity.needsStupidWritePermissions(path)) { | ||||||
|                 val config = Config.newInstance(activity) |  | ||||||
|                 if (config.treeUri.isEmpty()) { |                 if (config.treeUri.isEmpty()) { | ||||||
|                     activity.runOnUiThread { |                     activity.runOnUiThread { | ||||||
|                         activity.toast(R.string.save_error_internal_storage) |                         activity.toast(R.string.save_error_internal_storage) | ||||||
| @@ -57,10 +60,8 @@ class PhotoProcessor(val activity: MainActivity, val uri: Uri?) : AsyncTask<Byte | |||||||
|             fos?.write(data) |             fos?.write(data) | ||||||
|             fos?.close() |             fos?.close() | ||||||
|             return photoFile.absolutePath |             return photoFile.absolutePath | ||||||
|         } catch (e: FileNotFoundException) { |         } catch (e: Exception) { | ||||||
|             Log.e(TAG, "PhotoProcessor file not found: $e") |             Log.e(TAG, "PhotoProcessor file not found: $e") | ||||||
|         } catch (e: IOException) { |  | ||||||
|             Log.e(TAG, "PhotoProcessor ioexception $e") |  | ||||||
|         } finally { |         } finally { | ||||||
|             try { |             try { | ||||||
|                 fos?.close() |                 fos?.close() | ||||||
| @@ -74,8 +75,7 @@ class PhotoProcessor(val activity: MainActivity, val uri: Uri?) : AsyncTask<Byte | |||||||
|  |  | ||||||
|     override fun onPostExecute(path: String) { |     override fun onPostExecute(path: String) { | ||||||
|         super.onPostExecute(path) |         super.onPostExecute(path) | ||||||
|         val listener = mActivity?.get() |         mActivity?.get()?.mediaSaved(path) | ||||||
|         listener?.mediaSaved(path) |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     interface MediaSavedListener { |     interface MediaSavedListener { | ||||||
|   | |||||||
| @@ -29,7 +29,7 @@ import java.util.* | |||||||
|  |  | ||||||
| class Preview : ViewGroup, SurfaceHolder.Callback, MediaScannerConnection.OnScanCompletedListener { | class Preview : ViewGroup, SurfaceHolder.Callback, MediaScannerConnection.OnScanCompletedListener { | ||||||
|     companion object { |     companion object { | ||||||
|         val PHOTO_PREVIEW_LENGTH = 1000 |         val PHOTO_PREVIEW_LENGTH = 1000L | ||||||
|         private val TAG = Preview::class.java.simpleName |         private val TAG = Preview::class.java.simpleName | ||||||
|         private val FOCUS_AREA_SIZE = 100 |         private val FOCUS_AREA_SIZE = 100 | ||||||
|  |  | ||||||
| @@ -203,9 +203,7 @@ class Preview : ViewGroup, SurfaceHolder.Callback, MediaScannerConnection.OnScan | |||||||
|                 newZoomFactor = Math.min(mMaxZoom, newZoomFactor) |                 newZoomFactor = Math.min(mMaxZoom, newZoomFactor) | ||||||
|  |  | ||||||
|                 mParameters!!.zoom = newZoomFactor |                 mParameters!!.zoom = newZoomFactor | ||||||
|                 if (mCamera != null) |                 mCamera?.parameters = mParameters | ||||||
|                     mCamera!!.parameters = mParameters |  | ||||||
|  |  | ||||||
|                 return true |                 return true | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -248,7 +246,9 @@ class Preview : ViewGroup, SurfaceHolder.Callback, MediaScannerConnection.OnScan | |||||||
|  |  | ||||||
|     private val takePictureCallback = Camera.PictureCallback { data, cam -> |     private val takePictureCallback = Camera.PictureCallback { data, cam -> | ||||||
|         if (config.isShowPreviewEnabled) { |         if (config.isShowPreviewEnabled) { | ||||||
|             Handler().postDelayed({ resumePreview() }, PHOTO_PREVIEW_LENGTH.toLong()) |             Handler().postDelayed({ | ||||||
|  |                 resumePreview() | ||||||
|  |             }, PHOTO_PREVIEW_LENGTH) | ||||||
|         } else { |         } else { | ||||||
|             resumePreview() |             resumePreview() | ||||||
|         } |         } | ||||||
| @@ -261,13 +261,7 @@ class Preview : ViewGroup, SurfaceHolder.Callback, MediaScannerConnection.OnScan | |||||||
|         mCanTakePicture = true |         mCanTakePicture = true | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun getSupportedVideoSizes(): List<Camera.Size> { |     fun getSupportedVideoSizes(): List<Camera.Size> = mParameters!!.supportedVideoSizes ?: mParameters!!.supportedPreviewSizes | ||||||
|         return if (mParameters!!.supportedVideoSizes != null) { |  | ||||||
|             mParameters!!.supportedVideoSizes |  | ||||||
|         } else { |  | ||||||
|             mParameters!!.supportedPreviewSizes |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     private fun focusArea(takePictureAfter: Boolean) { |     private fun focusArea(takePictureAfter: Boolean) { | ||||||
|         if (mCamera == null) |         if (mCamera == null) | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ import android.content.pm.PackageManager | |||||||
| import android.content.res.Resources | import android.content.res.Resources | ||||||
| import android.database.Cursor | import android.database.Cursor | ||||||
| import android.hardware.* | import android.hardware.* | ||||||
| import android.media.MediaScannerConnection |  | ||||||
| import android.net.Uri | import android.net.Uri | ||||||
| import android.os.Build | import android.os.Build | ||||||
| import android.os.Bundle | import android.os.Bundle | ||||||
| @@ -29,11 +28,11 @@ import com.simplemobiletools.commons.models.Release | |||||||
| import kotlinx.android.synthetic.main.activity_main.* | import kotlinx.android.synthetic.main.activity_main.* | ||||||
| import java.util.* | import java.util.* | ||||||
|  |  | ||||||
| class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, PhotoProcessor.MediaSavedListener, MediaScannerConnection.OnScanCompletedListener { | class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, PhotoProcessor.MediaSavedListener { | ||||||
|     companion object { |     companion object { | ||||||
|  |  | ||||||
|         private val CAMERA_STORAGE_PERMISSION = 1 |         private val CAMERA_STORAGE_PERMISSION = 1 | ||||||
|         private val AUDIO_PERMISSION = 2 |         private val RECORD_AUDIO_PERMISSION = 2 | ||||||
|         private val FADE_DELAY = 5000 |         private val FADE_DELAY = 5000 | ||||||
|  |  | ||||||
|         lateinit var mSensorManager: SensorManager |         lateinit var mSensorManager: SensorManager | ||||||
| @@ -107,19 +106,17 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun handleIntent() { |     private fun handleIntent() { | ||||||
|         if (intent?.action != null) { |         if (intent?.action == MediaStore.ACTION_IMAGE_CAPTURE || intent?.action == MediaStore.ACTION_IMAGE_CAPTURE_SECURE) { | ||||||
|             if (intent.action == MediaStore.ACTION_IMAGE_CAPTURE || intent.action == MediaStore.ACTION_IMAGE_CAPTURE_SECURE) { |             mIsImageCaptureIntent = true | ||||||
|                 mIsImageCaptureIntent = true |             hideToggleModeAbout() | ||||||
|                 hideToggleModeAbout() |             val output = intent.extras.get(MediaStore.EXTRA_OUTPUT) | ||||||
|                 val output = intent.extras.get(MediaStore.EXTRA_OUTPUT) |             if (output != null && output is Uri) { | ||||||
|                 if (output != null && output is Uri) { |                 mPreview?.setTargetUri(output) | ||||||
|                     mPreview?.setTargetUri(output) |  | ||||||
|                 } |  | ||||||
|             } else if (intent.action == MediaStore.ACTION_VIDEO_CAPTURE) { |  | ||||||
|                 mIsVideoCaptureIntent = true |  | ||||||
|                 hideToggleModeAbout() |  | ||||||
|                 shutter.setImageDrawable(mRes.getDrawable(R.drawable.ic_video_rec)) |  | ||||||
|             } |             } | ||||||
|  |         } else if (intent?.action == MediaStore.ACTION_VIDEO_CAPTURE) { | ||||||
|  |             mIsVideoCaptureIntent = true | ||||||
|  |             hideToggleModeAbout() | ||||||
|  |             shutter.setImageDrawable(mRes.getDrawable(R.drawable.ic_video_rec)) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -172,7 +169,7 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|                 toast(R.string.no_permissions) |                 toast(R.string.no_permissions) | ||||||
|                 finish() |                 finish() | ||||||
|             } |             } | ||||||
|         } else if (requestCode == AUDIO_PERMISSION) { |         } else if (requestCode == RECORD_AUDIO_PERMISSION) { | ||||||
|             if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { |             if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||||
|                 togglePhotoVideo() |                 togglePhotoVideo() | ||||||
|             } else { |             } else { | ||||||
| @@ -268,15 +265,17 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|         if (mIsInPhotoMode) { |         if (mIsInPhotoMode) { | ||||||
|             toggleBottomButtons(true) |             toggleBottomButtons(true) | ||||||
|             mPreview?.takePicture() |             mPreview?.takePicture() | ||||||
|             Handler().postDelayed({ toggleBottomButtons(false) }, Preview.PHOTO_PREVIEW_LENGTH.toLong()) |             Handler().postDelayed({ | ||||||
|  |                 toggleBottomButtons(false) | ||||||
|  |             }, Preview.PHOTO_PREVIEW_LENGTH) | ||||||
|         } else { |         } else { | ||||||
|             if (mPreview?.toggleRecording() == true) { |             if (mPreview?.toggleRecording() == true) { | ||||||
|                 shutter.setImageDrawable(mRes.getDrawable(R.drawable.ic_video_stop)) |                 shutter.setImageDrawable(mRes.getDrawable(R.drawable.ic_video_stop)) | ||||||
|                 toggle_camera.visibility = View.INVISIBLE |                 toggle_camera.beInvisible() | ||||||
|                 showTimer() |                 showTimer() | ||||||
|             } else { |             } else { | ||||||
|                 shutter.setImageDrawable(mRes.getDrawable(R.drawable.ic_video_rec)) |                 shutter.setImageDrawable(mRes.getDrawable(R.drawable.ic_video_rec)) | ||||||
|                 toggle_camera.visibility = View.VISIBLE |                 toggle_camera.beVisible() | ||||||
|                 hideTimer() |                 hideTimer() | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -309,7 +308,7 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!hasRecordAudioPermission()) { |         if (!hasRecordAudioPermission()) { | ||||||
|             ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO), AUDIO_PERMISSION) |             ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO), RECORD_AUDIO_PERMISSION) | ||||||
|             mIsAskingPermissions = true |             mIsAskingPermissions = true | ||||||
|             return |             return | ||||||
|         } |         } | ||||||
| @@ -320,7 +319,7 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|         disableFlash() |         disableFlash() | ||||||
|         hideTimer() |         hideTimer() | ||||||
|         mIsInPhotoMode = !mIsInPhotoMode |         mIsInPhotoMode = !mIsInPhotoMode | ||||||
|         toggle_camera.visibility = View.VISIBLE |         toggle_camera.beVisible() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun checkButtons() { |     private fun checkButtons() { | ||||||
| @@ -350,7 +349,7 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|  |  | ||||||
|     private fun initVideoButtons() { |     private fun initVideoButtons() { | ||||||
|         toggle_photo_video.setImageDrawable(mRes.getDrawable(R.drawable.ic_camera)) |         toggle_photo_video.setImageDrawable(mRes.getDrawable(R.drawable.ic_camera)) | ||||||
|         toggle_camera.visibility = View.VISIBLE |         toggle_camera.beVisible() | ||||||
|         shutter.setImageDrawable(mRes.getDrawable(R.drawable.ic_video_rec)) |         shutter.setImageDrawable(mRes.getDrawable(R.drawable.ic_video_rec)) | ||||||
|         checkFlash() |         checkFlash() | ||||||
|         setupPreviewImage(false) |         setupPreviewImage(false) | ||||||
| @@ -365,7 +364,7 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|         mPreviewUri = Uri.withAppendedPath(uri, lastMediaId.toString()) |         mPreviewUri = Uri.withAppendedPath(uri, lastMediaId.toString()) | ||||||
|  |  | ||||||
|         runOnUiThread { |         runOnUiThread { | ||||||
|             if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1 || !isDestroyed) { |             if (!isDestroyed || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { | ||||||
|                 Glide.with(this).load(mPreviewUri).centerCrop().diskCacheStrategy(DiskCacheStrategy.NONE).crossFade().into(last_photo_video_preview) |                 Glide.with(this).load(mPreviewUri).centerCrop().diskCacheStrategy(DiskCacheStrategy.NONE).crossFade().into(last_photo_video_preview) | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| @@ -376,9 +375,8 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|         var cursor: Cursor? = null |         var cursor: Cursor? = null | ||||||
|         try { |         try { | ||||||
|             cursor = contentResolver.query(uri, projection, null, null, "${MediaStore.Images.ImageColumns.DATE_TAKEN} DESC") |             cursor = contentResolver.query(uri, projection, null, null, "${MediaStore.Images.ImageColumns.DATE_TAKEN} DESC") | ||||||
|             if (cursor != null && cursor.moveToFirst()) { |             if (cursor?.moveToFirst() == true) { | ||||||
|                 val idIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID) |                 return cursor.getLongValue(MediaStore.Images.ImageColumns._ID) | ||||||
|                 return cursor.getLong(idIndex) |  | ||||||
|             } |             } | ||||||
|         } finally { |         } finally { | ||||||
|             cursor?.close() |             cursor?.close() | ||||||
| @@ -412,13 +410,13 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|  |  | ||||||
|     private fun hideTimer() { |     private fun hideTimer() { | ||||||
|         video_rec_curr_timer.text = 0.getFormattedDuration() |         video_rec_curr_timer.text = 0.getFormattedDuration() | ||||||
|         video_rec_curr_timer.visibility = View.GONE |         video_rec_curr_timer.beGone() | ||||||
|         mCurrVideoRecTimer = 0 |         mCurrVideoRecTimer = 0 | ||||||
|         mTimerHandler.removeCallbacksAndMessages(null) |         mTimerHandler.removeCallbacksAndMessages(null) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private fun showTimer() { |     private fun showTimer() { | ||||||
|         video_rec_curr_timer.visibility = View.VISIBLE |         video_rec_curr_timer.beVisible() | ||||||
|         setupTimer() |         setupTimer() | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -449,7 +447,7 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|     private fun resumeCameraItems() { |     private fun resumeCameraItems() { | ||||||
|         val cnt = Camera.getNumberOfCameras() |         val cnt = Camera.getNumberOfCameras() | ||||||
|         if (cnt == 1) { |         if (cnt == 1) { | ||||||
|             toggle_camera.visibility = View.INVISIBLE |             toggle_camera.beInvisible() | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (mPreview?.setCamera(mCurrCamera) == true) { |         if (mPreview?.setCamera(mCurrCamera) == true) { | ||||||
| @@ -482,19 +480,19 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|  |  | ||||||
|     override fun onSensorChanged(event: SensorEvent) { |     override fun onSensorChanged(event: SensorEvent) { | ||||||
|         if (event.values[0] < 6.5 && event.values[0] > -6.5) { |         if (event.values[0] < 6.5 && event.values[0] > -6.5) { | ||||||
|             mOrientation = Constants.ORIENT_PORTRAIT |             mOrientation = ORIENT_PORTRAIT | ||||||
|         } else { |         } else { | ||||||
|             if (event.values[0] > 0) { |             if (event.values[0] > 0) { | ||||||
|                 mOrientation = Constants.ORIENT_LANDSCAPE_LEFT |                 mOrientation = ORIENT_LANDSCAPE_LEFT | ||||||
|             } else { |             } else { | ||||||
|                 mOrientation = Constants.ORIENT_LANDSCAPE_RIGHT |                 mOrientation = ORIENT_LANDSCAPE_RIGHT | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (mOrientation != mLastHandledOrientation) { |         if (mOrientation != mLastHandledOrientation) { | ||||||
|             val degrees = when (mOrientation) { |             val degrees = when (mOrientation) { | ||||||
|                 Constants.ORIENT_LANDSCAPE_LEFT -> 90 |                 ORIENT_LANDSCAPE_LEFT -> 90 | ||||||
|                 Constants.ORIENT_LANDSCAPE_RIGHT -> -90 |                 ORIENT_LANDSCAPE_RIGHT -> -90 | ||||||
|                 else -> 0 |                 else -> 0 | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -524,9 +522,9 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|  |  | ||||||
|     override fun setFlashAvailable(available: Boolean) { |     override fun setFlashAvailable(available: Boolean) { | ||||||
|         if (available) { |         if (available) { | ||||||
|             toggle_flash.visibility = View.VISIBLE |             toggle_flash.beVisible() | ||||||
|         } else { |         } else { | ||||||
|             toggle_flash.visibility = View.INVISIBLE |             toggle_flash.beInvisible() | ||||||
|             disableFlash() |             disableFlash() | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @@ -552,8 +550,9 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|     override fun drawFocusRect(x: Int, y: Int) = mFocusRectView.drawFocusRect(x, y) |     override fun drawFocusRect(x: Int, y: Int) = mFocusRectView.drawFocusRect(x, y) | ||||||
|  |  | ||||||
|     override fun mediaSaved(path: String) { |     override fun mediaSaved(path: String) { | ||||||
|         val paths = arrayOf(path) |         scanPath(path) { | ||||||
|         MediaScannerConnection.scanFile(applicationContext, paths, null, this) |             setupPreviewImage(mIsInPhotoMode) | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (mIsImageCaptureIntent) { |         if (mIsImageCaptureIntent) { | ||||||
|             setResult(Activity.RESULT_OK) |             setResult(Activity.RESULT_OK) | ||||||
| @@ -567,8 +566,6 @@ class MainActivity : SimpleActivity(), SensorEventListener, PreviewListener, Pho | |||||||
|         mPreview?.releaseCamera() |         mPreview?.releaseCamera() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun onScanCompleted(path: String, uri: Uri) = setupPreviewImage(mIsInPhotoMode) |  | ||||||
|  |  | ||||||
|     private fun checkWhatsNewDialog() { |     private fun checkWhatsNewDialog() { | ||||||
|         arrayListOf<Release>().apply { |         arrayListOf<Release>().apply { | ||||||
|             add(Release(33, R.string.release_33)) |             add(Release(33, R.string.release_33)) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user