Skip to content

Commit e4e2f91

Browse files
authored
Merge pull request #226 from wordpress-mobile/issue/218-uploading-images
Issue/218 uploading images
2 parents cde2466 + cec412f commit e4e2f91

File tree

13 files changed

+1212
-362
lines changed

13 files changed

+1212
-362
lines changed

app/src/main/kotlin/org/wordpress/aztec/demo/MainActivity.kt

Lines changed: 215 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,19 @@ import android.content.res.Configuration
99
import android.graphics.Bitmap
1010
import android.graphics.BitmapFactory
1111
import android.graphics.drawable.BitmapDrawable
12+
import android.graphics.drawable.ColorDrawable
1213
import android.net.Uri
1314
import android.os.Build
1415
import android.os.Bundle
1516
import android.os.Environment
17+
import android.os.Handler
1618
import android.provider.MediaStore
1719
import android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback
1820
import android.support.v4.content.FileProvider
21+
import android.support.v7.app.AlertDialog
1922
import android.support.v7.app.AppCompatActivity
20-
import android.view.Menu
21-
import android.view.MenuItem
22-
import android.view.MotionEvent
23-
import android.view.View
23+
import android.view.*
24+
import android.widget.PopupMenu
2425
import android.widget.Toast
2526
import org.wordpress.android.util.AppLog
2627
import org.wordpress.android.util.PermissionUtils
@@ -29,11 +30,14 @@ import org.wordpress.aztec.AztecText
2930
import org.wordpress.aztec.picassoloader.PicassoImageLoader
3031
import org.wordpress.aztec.source.SourceViewEditText
3132
import org.wordpress.aztec.toolbar.AztecToolbar
32-
import org.wordpress.aztec.toolbar.AztecToolbar.OnMediaOptionSelectedListener
33+
import org.wordpress.aztec.toolbar.AztecToolbarClickListener
34+
import org.xml.sax.Attributes
35+
import org.xml.sax.helpers.AttributesImpl
3336
import java.io.File
3437

35-
class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnRequestPermissionsResultCallback,
36-
View.OnTouchListener, AztecText.OnImeBackListener {
38+
class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback, View.OnTouchListener,
39+
PopupMenu.OnMenuItemClickListener, AztecToolbarClickListener, AztecText.OnMediaTappedListener,
40+
AztecText.OnImeBackListener {
3741
companion object {
3842
private val HEADING =
3943
"<h1>Heading 1</h1>" +
@@ -105,6 +109,11 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
105109
private lateinit var source: SourceViewEditText
106110
private lateinit var formattingToolbar: AztecToolbar
107111

112+
private var addPhotoMediaDialog: AlertDialog? = null
113+
private var addVideoMediaDialog: AlertDialog? = null
114+
private var mediaUploadDialog: AlertDialog? = null
115+
private var mediaMenu: PopupMenu? = null
116+
108117
private var mIsKeyboardOpen = false
109118
private var mHideActionBarOnSoftKeyboardUp = false
110119

@@ -127,13 +136,57 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
127136
}
128137
}
129138

130-
val source = mediaPath // Temporary source value. Replace with URL after uploaded.
131-
aztec.lineBlockFormatter.insertMedia(BitmapDrawable(resources, bitmap), source)
139+
insertMediaAndSimulateUpload(bitmap, mediaPath)
132140
}
133141

134142
super.onActivityResult(requestCode, resultCode, data)
135143
}
136144

145+
fun insertMediaAndSimulateUpload(bitmap: Bitmap?, mediaPath: String) {
146+
val id = (Math.random() * Int.MAX_VALUE).toString()
147+
148+
val attrs = AttributesImpl()
149+
attrs.addAttribute("", "src", "src", "string", mediaPath) // Temporary source value. Replace with URL after uploaded.
150+
attrs.addAttribute("", "id", "id", "string", id)
151+
attrs.addAttribute("", "uploading", "uploading", "string", "true")
152+
153+
aztec.insertMedia(BitmapDrawable(resources, bitmap), attrs)
154+
155+
val predicate = object : AztecText.AttributePredicate {
156+
override fun matches(attrs: Attributes): Boolean {
157+
return attrs.getValue("id") == id
158+
}
159+
}
160+
161+
aztec.setOverlay(predicate, 0, ColorDrawable(0x80000000.toInt()), Gravity.FILL, attrs)
162+
val progressDrawable = resources.getDrawable(android.R.drawable.progress_horizontal)
163+
// set the height of the progress bar to 2 (it's in dp since the drawable will be adjusted by the span)
164+
progressDrawable.setBounds(0, 0, 0, 4)
165+
aztec.setOverlay(predicate, 1, progressDrawable, Gravity.FILL_HORIZONTAL or Gravity.TOP, attrs)
166+
167+
var progress = 0
168+
169+
// simulate an upload delay
170+
val runnable: Runnable = Runnable {
171+
aztec.setOverlayLevel(predicate, 1, progress, attrs)
172+
aztec.refreshText()
173+
progress += 2000
174+
175+
if (progress >= 10000) {
176+
attrs.removeAttribute(attrs.getIndex("uploading"))
177+
aztec.clearOverlays(predicate, attrs)
178+
}
179+
}
180+
181+
Handler().post(runnable);
182+
Handler().postDelayed(runnable, 2000);
183+
Handler().postDelayed(runnable, 4000);
184+
Handler().postDelayed(runnable, 6000);
185+
Handler().postDelayed(runnable, 8000);
186+
187+
aztec.refreshText()
188+
}
189+
137190
override fun onCreate(savedInstanceState: Bundle?) {
138191
super.onCreate(savedInstanceState)
139192
setContentView(R.layout.activity_main)
@@ -153,7 +206,7 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
153206

154207
formattingToolbar = findViewById(R.id.formatting_toolbar) as AztecToolbar
155208
formattingToolbar.setEditor(aztec, source)
156-
formattingToolbar.setMediaOptionSelectedListener(this)
209+
formattingToolbar.setToolbarListener(this)
157210

158211
// initialize the text & HTML
159212
source.displayStyledAndFormattedHtml(EXAMPLE)
@@ -165,6 +218,8 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
165218
aztec.setOnTouchListener(this)
166219
source.setOnImeBackListener(this)
167220
source.setOnTouchListener(this)
221+
222+
aztec.setOnMediaTappedListener(this)
168223
}
169224

170225
override fun onPause() {
@@ -192,6 +247,40 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
192247
}
193248
}
194249

250+
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
251+
super.onRestoreInstanceState(savedInstanceState)
252+
253+
savedInstanceState?.let {
254+
if (savedInstanceState.getBoolean("isPhotoMediaDialogVisible")) {
255+
showPhotoMediaDialog()
256+
}
257+
258+
if (savedInstanceState.getBoolean("isVideoMediaDialogVisible")) {
259+
showVideoMediaDialog()
260+
}
261+
262+
if (savedInstanceState.getBoolean("isMediaUploadDialogVisible")) {
263+
showMediaUploadDialog()
264+
}
265+
}
266+
}
267+
268+
override fun onSaveInstanceState(outState: Bundle?) {
269+
super.onSaveInstanceState(outState)
270+
271+
if (addPhotoMediaDialog != null && addPhotoMediaDialog!!.isShowing) {
272+
outState?.putBoolean("isPhotoMediaDialogVisible", true)
273+
}
274+
275+
if (addVideoMediaDialog != null && addVideoMediaDialog!!.isShowing) {
276+
outState?.putBoolean("isVideoMediaDialogVisible", true)
277+
}
278+
279+
if (mediaUploadDialog != null && mediaUploadDialog!!.isShowing) {
280+
outState?.putBoolean("isMediaUploadDialogVisible", true)
281+
}
282+
}
283+
195284
/**
196285
* Returns true if a hardware keyboard is detected, otherwise false.
197286
*/
@@ -278,7 +367,7 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
278367
return true
279368
}
280369

281-
override fun onCameraPhotoMediaOptionSelected() {
370+
fun onCameraPhotoMediaOptionSelected() {
282371
if (PermissionUtils.checkAndRequestCameraAndStoragePermissions(this, MEDIA_CAMERA_PHOTO_PERMISSION_REQUEST_CODE)) {
283372
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
284373

@@ -294,7 +383,7 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
294383
}
295384
}
296385

297-
override fun onCameraVideoMediaOptionSelected() {
386+
fun onCameraVideoMediaOptionSelected() {
298387
if (PermissionUtils.checkAndRequestCameraAndStoragePermissions(this, MEDIA_CAMERA_PHOTO_PERMISSION_REQUEST_CODE)) {
299388
val intent = Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA)
300389

@@ -304,15 +393,15 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
304393
}
305394
}
306395

307-
override fun onGalleryMediaOptionSelected() {
396+
fun onGalleryMediaOptionSelected() {
308397
Toast.makeText(this, "Launch gallery", Toast.LENGTH_SHORT).show()
309398
}
310399

311-
override fun onPhotoLibraryMediaOptionSelected() {
400+
fun onPhotoLibraryMediaOptionSelected() {
312401
Toast.makeText(this, "Open library", Toast.LENGTH_SHORT).show()
313402
}
314403

315-
override fun onPhotosMediaOptionSelected() {
404+
fun onPhotosMediaOptionSelected() {
316405
if (PermissionUtils.checkAndRequestStoragePermission(this, MEDIA_PHOTOS_PERMISSION_REQUEST_CODE)) {
317406
val intent: Intent
318407

@@ -334,11 +423,11 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
334423
}
335424
}
336425

337-
override fun onVideoLibraryMediaOptionSelected() {
426+
fun onVideoLibraryMediaOptionSelected() {
338427
Toast.makeText(this, "Open library", Toast.LENGTH_SHORT).show()
339428
}
340429

341-
override fun onVideosMediaOptionSelected() {
430+
fun onVideosMediaOptionSelected() {
342431
if (PermissionUtils.checkAndRequestStoragePermission(this, MEDIA_PHOTOS_PERMISSION_REQUEST_CODE)) {
343432
val intent: Intent
344433

@@ -431,4 +520,113 @@ class MainActivity : AppCompatActivity(), OnMediaOptionSelectedListener, OnReque
431520

432521
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
433522
}
523+
524+
override fun onToolbarHtmlModeClicked() {
525+
val uploadingPredicate = object : AztecText.AttributePredicate {
526+
override fun matches(attrs: Attributes): Boolean {
527+
return attrs.getIndex("uploading") > -1
528+
}
529+
}
530+
531+
val mediaPending = aztec.getAllMediaAttributes(uploadingPredicate).size > 0
532+
533+
if (mediaPending) {
534+
ToastUtils.showToast(this, R.string.media_upload_dialog_message)
535+
} else {
536+
formattingToolbar.toggleEditorMode()
537+
}
538+
}
539+
540+
override fun onToolbarAddMediaClicked() {
541+
mediaMenu = PopupMenu(this, formattingToolbar)
542+
mediaMenu?.setOnMenuItemClickListener(this)
543+
mediaMenu?.inflate(R.menu.media)
544+
mediaMenu?.show()
545+
}
546+
547+
override fun onMenuItemClick(item: MenuItem?): Boolean {
548+
item?.isChecked = (item?.isChecked == false)
549+
550+
when (item?.itemId) {
551+
org.wordpress.aztec.R.id.gallery -> {
552+
onGalleryMediaOptionSelected()
553+
return true
554+
}
555+
org.wordpress.aztec.R.id.photo -> {
556+
showPhotoMediaDialog()
557+
return true
558+
}
559+
org.wordpress.aztec.R.id.video -> {
560+
showVideoMediaDialog()
561+
return true
562+
}
563+
else -> return false
564+
}
565+
}
566+
567+
private fun showMediaUploadDialog() {
568+
val builder = AlertDialog.Builder(this)
569+
builder.setMessage(getString(org.wordpress.aztec.R.string.media_upload_dialog_message))
570+
builder.setPositiveButton(getString(org.wordpress.aztec.R.string.media_upload_dialog_positive), null)
571+
mediaUploadDialog = builder.create()
572+
mediaUploadDialog!!.show()
573+
}
574+
575+
private fun showPhotoMediaDialog() {
576+
val dialog = layoutInflater.inflate(R.layout.dialog_photo_media, null)
577+
578+
val camera = dialog.findViewById(org.wordpress.aztec.R.id.media_camera)
579+
camera.setOnClickListener({
580+
onCameraPhotoMediaOptionSelected()
581+
addPhotoMediaDialog?.dismiss()
582+
})
583+
584+
val photos = dialog.findViewById(org.wordpress.aztec.R.id.media_photos)
585+
photos.setOnClickListener({
586+
onPhotosMediaOptionSelected()
587+
addPhotoMediaDialog?.dismiss()
588+
})
589+
590+
val library = dialog.findViewById(org.wordpress.aztec.R.id.media_library)
591+
library.setOnClickListener({
592+
onPhotoLibraryMediaOptionSelected()
593+
addPhotoMediaDialog?.dismiss()
594+
})
595+
596+
val builder = AlertDialog.Builder(this)
597+
builder.setView(dialog)
598+
addPhotoMediaDialog = builder.create()
599+
addPhotoMediaDialog!!.show()
600+
}
601+
602+
private fun showVideoMediaDialog() {
603+
val dialog = layoutInflater.inflate(org.wordpress.aztec.R.layout.dialog_video_media, null)
604+
605+
val camera = dialog.findViewById(org.wordpress.aztec.R.id.media_camera)
606+
camera.setOnClickListener({
607+
onCameraVideoMediaOptionSelected()
608+
addVideoMediaDialog?.dismiss()
609+
})
610+
611+
val videos = dialog.findViewById(org.wordpress.aztec.R.id.media_videos)
612+
videos.setOnClickListener({
613+
onVideosMediaOptionSelected()
614+
addVideoMediaDialog?.dismiss()
615+
})
616+
617+
val library = dialog.findViewById(org.wordpress.aztec.R.id.media_library)
618+
library.setOnClickListener({
619+
onVideoLibraryMediaOptionSelected()
620+
addVideoMediaDialog?.dismiss()
621+
})
622+
623+
val builder = AlertDialog.Builder(this)
624+
builder.setView(dialog)
625+
addVideoMediaDialog = builder.create()
626+
addVideoMediaDialog!!.show()
627+
}
628+
629+
override fun mediaTapped(attrs: Attributes?, naturalWidth: Int, naturalHeight: Int) {
630+
ToastUtils.showToast(this, "Media tapped!")
631+
}
434632
}

0 commit comments

Comments
 (0)