Skip to content

Commit 6bc6290

Browse files
authored
Merge branch 'develop' into issue/181-update-placeholder-images
2 parents 2c9bf14 + 4dcd7c1 commit 6bc6290

39 files changed

+2192
-241
lines changed

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

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ import android.support.v4.app.ActivityCompat.OnRequestPermissionsResultCallback
2020
import android.support.v4.content.FileProvider
2121
import android.support.v7.app.AlertDialog
2222
import android.support.v7.app.AppCompatActivity
23+
import android.util.DisplayMetrics
2324
import android.view.*
2425
import android.widget.PopupMenu
2526
import android.widget.Toast
2627
import org.wordpress.android.util.AppLog
2728
import org.wordpress.android.util.PermissionUtils
2829
import org.wordpress.android.util.ToastUtils
2930
import org.wordpress.aztec.AztecText
31+
import org.wordpress.aztec.HistoryListener
3032
import org.wordpress.aztec.picassoloader.PicassoImageLoader
3133
import org.wordpress.aztec.source.SourceViewEditText
3234
import org.wordpress.aztec.toolbar.AztecToolbar
@@ -35,9 +37,14 @@ import org.xml.sax.Attributes
3537
import org.xml.sax.helpers.AttributesImpl
3638
import java.io.File
3739

38-
class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback, View.OnTouchListener,
39-
PopupMenu.OnMenuItemClickListener, AztecToolbarClickListener, AztecText.OnMediaTappedListener,
40-
AztecText.OnImeBackListener {
40+
class MainActivity : AppCompatActivity(),
41+
AztecText.OnImeBackListener,
42+
AztecText.OnMediaTappedListener,
43+
AztecToolbarClickListener,
44+
HistoryListener,
45+
OnRequestPermissionsResultCallback,
46+
PopupMenu.OnMenuItemClickListener,
47+
View.OnTouchListener {
4148
companion object {
4249
private val HEADING =
4350
"<h1>Heading 1</h1>" +
@@ -109,6 +116,9 @@ class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback, Vi
109116
private lateinit var source: SourceViewEditText
110117
private lateinit var formattingToolbar: AztecToolbar
111118

119+
private lateinit var invalidateOptionsHandler: Handler
120+
private lateinit var invalidateOptionsRunnable: Runnable
121+
112122
private var addPhotoMediaDialog: AlertDialog? = null
113123
private var addVideoMediaDialog: AlertDialog? = null
114124
private var mediaUploadDialog: AlertDialog? = null
@@ -123,14 +133,22 @@ class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback, Vi
123133

124134
when (requestCode) {
125135
REQUEST_MEDIA_CAMERA_PHOTO -> {
126-
bitmap = BitmapFactory.decodeFile(mediaPath)
136+
// By default, BitmapFactory.decodeFile sets the bitmap's density to the device default so, we need
137+
// to correctly set the input density to 160 ourselves.
138+
val options = BitmapFactory.Options()
139+
options.inDensity = DisplayMetrics.DENSITY_DEFAULT
140+
bitmap = BitmapFactory.decodeFile(mediaPath, options)
127141
}
128142
REQUEST_MEDIA_CAMERA_VIDEO -> {
129143
}
130144
REQUEST_MEDIA_PHOTO -> {
131145
mediaPath = data?.data.toString()
132146
val stream = contentResolver.openInputStream(Uri.parse(mediaPath))
133-
bitmap = BitmapFactory.decodeStream(stream)
147+
// By default, BitmapFactory.decodeFile sets the bitmap's density to the device default so, we need
148+
// to correctly set the input density to 160 ourselves.
149+
val options = BitmapFactory.Options()
150+
options.inDensity = DisplayMetrics.DENSITY_DEFAULT
151+
bitmap = BitmapFactory.decodeStream(stream, null, options)
134152
}
135153
REQUEST_MEDIA_VIDEO -> {
136154
}
@@ -178,11 +196,11 @@ class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback, Vi
178196
}
179197
}
180198

181-
Handler().post(runnable);
182-
Handler().postDelayed(runnable, 2000);
183-
Handler().postDelayed(runnable, 4000);
184-
Handler().postDelayed(runnable, 6000);
185-
Handler().postDelayed(runnable, 8000);
199+
Handler().post(runnable)
200+
Handler().postDelayed(runnable, 2000)
201+
Handler().postDelayed(runnable, 4000)
202+
Handler().postDelayed(runnable, 6000)
203+
Handler().postDelayed(runnable, 8000)
186204

187205
aztec.refreshText()
188206
}
@@ -209,17 +227,24 @@ class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback, Vi
209227
formattingToolbar = findViewById(R.id.formatting_toolbar) as AztecToolbar
210228
formattingToolbar.setEditor(aztec, source)
211229
formattingToolbar.setToolbarListener(this)
230+
aztec.setToolbar(formattingToolbar)
212231

213232
// initialize the text & HTML
214233
source.displayStyledAndFormattedHtml(EXAMPLE)
215-
aztec.fromHtml(source.getPureHtml())
216234

217-
source.history = aztec.history
235+
if (savedInstanceState == null) {
236+
aztec.fromHtml(source.getPureHtml())
237+
source.history = aztec.history
238+
}
218239

240+
aztec.history.setHistoryListener(this)
219241
aztec.setOnImeBackListener(this)
220242
aztec.setOnTouchListener(this)
221243
source.setOnImeBackListener(this)
222244
source.setOnTouchListener(this)
245+
246+
invalidateOptionsHandler = Handler()
247+
invalidateOptionsRunnable = Runnable { invalidateOptionsMenu() }
223248
}
224249

225250
override fun onPause() {
@@ -250,6 +275,8 @@ class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback, Vi
250275
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
251276
super.onRestoreInstanceState(savedInstanceState)
252277

278+
source.history = aztec.history
279+
253280
savedInstanceState?.let {
254281
if (savedInstanceState.getBoolean("isPhotoMediaDialogVisible")) {
255282
showPhotoMediaDialog()
@@ -367,6 +394,22 @@ class MainActivity : AppCompatActivity(), OnRequestPermissionsResultCallback, Vi
367394
return true
368395
}
369396

397+
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
398+
menu?.findItem(R.id.redo)?.isEnabled = aztec.history.redoValid()
399+
menu?.findItem(R.id.undo)?.isEnabled = aztec.history.undoValid()
400+
return super.onPrepareOptionsMenu(menu)
401+
}
402+
403+
override fun onRedoEnabled() {
404+
invalidateOptionsHandler.removeCallbacks(invalidateOptionsRunnable)
405+
invalidateOptionsHandler.postDelayed(invalidateOptionsRunnable, resources.getInteger(android.R.integer.config_mediumAnimTime).toLong())
406+
}
407+
408+
override fun onUndoEnabled() {
409+
invalidateOptionsHandler.removeCallbacks(invalidateOptionsRunnable)
410+
invalidateOptionsHandler.postDelayed(invalidateOptionsRunnable, resources.getInteger(android.R.integer.config_mediumAnimTime).toLong())
411+
}
412+
370413
fun onCameraPhotoMediaOptionSelected() {
371414
if (PermissionUtils.checkAndRequestCameraAndStoragePermissions(this, MEDIA_CAMERA_PHOTO_PERMISSION_REQUEST_CODE)) {
372415
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<selector
4+
xmlns:android="http://schemas.android.com/apk/res/android" >
5+
6+
<item android:drawable="@drawable/ic_action_redo_white_30_24dp" android:state_enabled="false" />
7+
<item android:drawable="@drawable/ic_action_redo_white_24dp" />
8+
9+
</selector>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<vector
2+
xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:height="24dp"
4+
android:width="24dp"
5+
android:viewportHeight="24.0"
6+
android:viewportWidth="24.0" >
7+
8+
<path
9+
android:fillColor="#4dffffff"
10+
android:pathData="M18.4,10.6C16.55,8.99 14.15,8 11.5,8c-4.65,0 -8.58,3.03 -9.96,7.22L3.9,16c1.05,-3.19 4.05,-5.5 7.6,-5.5 1.95,0 3.73,0.72 5.12,1.88L13,16h9V7l-3.6,3.6z" >
11+
</path>
12+
13+
</vector>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
3+
<selector
4+
xmlns:android="http://schemas.android.com/apk/res/android" >
5+
6+
<item android:drawable="@drawable/ic_action_undo_white_30_24dp" android:state_enabled="false" />
7+
<item android:drawable="@drawable/ic_action_undo_white_24dp" />
8+
9+
</selector>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<vector
2+
xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:height="24dp"
4+
android:width="24dp"
5+
android:viewportHeight="24.0"
6+
android:viewportWidth="24.0" >
7+
8+
<path
9+
android:fillColor="#4dffffff"
10+
android:pathData="M12.5,8c-2.65,0 -5.05,0.99 -6.9,2.6L2,7v9h9l-3.62,-3.62c1.39,-1.16 3.16,-1.88 5.12,-1.88 3.54,0 6.55,2.31 7.6,5.5l2.37,-0.78C21.08,11.03 17.15,8 12.5,8z" >
11+
</path>
12+
13+
</vector>

app/src/main/res/menu/menu_main.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77

88
<item
99
android:id="@+id/undo"
10-
android:icon="@drawable/ic_action_undo_white_24dp"
10+
android:icon="@drawable/ic_action_undo_selector"
1111
android:title="@string/menu_undo"
1212
app:showAsAction="always"
1313
tools:ignore="AlwaysShowAction" >
1414
</item>
1515

1616
<item
1717
android:id="@+id/redo"
18-
android:icon="@drawable/ic_action_redo_white_24dp"
18+
android:icon="@drawable/ic_action_redo_selector"
1919
android:title="@string/menu_redo"
2020
app:showAsAction="always"
2121
tools:ignore="AlwaysShowAction" >

aztec/src/main/java/org/wordpress/aztec/Html.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ private Html() {
120120
* <p/>
121121
* <p>This uses TagSoup to handle real HTML, including all of the brokenness found in the wild.
122122
*/
123-
public static Spanned fromHtml(String source, OnMediaTappedListener onMediaTappedListener, Context context) {
124-
return fromHtml(source, null, onMediaTappedListener, context);
123+
public static Spanned fromHtml(String source, OnMediaTappedListener onMediaTappedListener,
124+
UnknownHtmlSpan.OnUnknownHtmlClickListener onUnknownHtmlClickListener, Context context) {
125+
return fromHtml(source, null, onMediaTappedListener, onUnknownHtmlClickListener, context);
125126
}
126127

127128
/**
@@ -143,7 +144,7 @@ private static class HtmlParser {
143144
* <p>This uses TagSoup to handle real HTML, including all of the brokenness found in the wild.
144145
*/
145146
public static Spanned fromHtml(String source, TagHandler tagHandler, OnMediaTappedListener onMediaTappedListener,
146-
Context context) {
147+
UnknownHtmlSpan.OnUnknownHtmlClickListener onUnknownHtmlClickListener, Context context) {
147148
Parser parser = new Parser();
148149
try {
149150
parser.setProperty(Parser.schemaProperty, HtmlParser.schema);
@@ -158,7 +159,7 @@ public static Spanned fromHtml(String source, TagHandler tagHandler, OnMediaTapp
158159

159160
HtmlToSpannedConverter converter =
160161
new HtmlToSpannedConverter(source, tagHandler,
161-
parser, onMediaTappedListener, context);
162+
parser, onMediaTappedListener, onUnknownHtmlClickListener, context);
162163
return converter.convert();
163164
}
164165

@@ -181,6 +182,7 @@ class HtmlToSpannedConverter implements ContentHandler, LexicalHandler {
181182
public Unknown unknown;
182183

183184
private String mSource;
185+
private UnknownHtmlSpan.OnUnknownHtmlClickListener onUnknownHtmlClickListener;
184186
private XMLReader mReader;
185187
private SpannableStringBuilder spannableStringBuilder;
186188
private Html.TagHandler tagHandler;
@@ -189,13 +191,15 @@ class HtmlToSpannedConverter implements ContentHandler, LexicalHandler {
189191

190192
public HtmlToSpannedConverter(
191193
String source, Html.TagHandler tagHandler,
192-
Parser parser, OnMediaTappedListener onMediaTappedListener, Context context) {
194+
Parser parser, OnMediaTappedListener onMediaTappedListener,
195+
UnknownHtmlSpan.OnUnknownHtmlClickListener onUnknownHtmlClickListener, Context context) {
193196
mSource = source;
194197
spannableStringBuilder = new SpannableStringBuilder();
195198
this.tagHandler = tagHandler;
196199
mReader = parser;
197200
this.context = context;
198201
this.onMediaTappedListener = onMediaTappedListener;
202+
this.onUnknownHtmlClickListener = onUnknownHtmlClickListener;
199203
}
200204

201205
public Spanned convert() {
@@ -312,14 +316,17 @@ private void handleEndTag(String tag) {
312316
if (unknownTagLevel != 0) {
313317
if (tag.equalsIgnoreCase("aztec_cursor")) {
314318
return; //already handled at start tag
319+
} else if (tag.equalsIgnoreCase("br")) {
320+
unknownTagLevel -= 1;
321+
return; //already handled at start tag
315322
}
316323
// Swallow closing tag in current Unknown element
317324
unknown.rawHtml.append("</").append(tag).append(">");
318325
unknownTagLevel -= 1;
319326
if (unknownTagLevel == 0) {
320327
// Time to wrap up our unknown tag in a Span
321328
spannableStringBuilder.append("\uFFFC"); // placeholder character
322-
endUnknown(spannableStringBuilder, unknown.rawHtml, context);
329+
endUnknown(spannableStringBuilder, unknown.rawHtml, context, onUnknownHtmlClickListener);
323330
}
324331
return;
325332
}
@@ -532,7 +539,8 @@ private static void endFont(SpannableStringBuilder text) {
532539
}
533540
}
534541

535-
private static void endUnknown(SpannableStringBuilder text, StringBuilder rawHtml, Context context) {
542+
private static void endUnknown(SpannableStringBuilder text, StringBuilder rawHtml, Context context,
543+
UnknownHtmlSpan.OnUnknownHtmlClickListener onUnknownHtmlClickListener) {
536544
int len = text.length();
537545
Object obj = getLast(text, Unknown.class);
538546
int where = text.getSpanStart(obj);
@@ -541,7 +549,7 @@ private static void endUnknown(SpannableStringBuilder text, StringBuilder rawHtm
541549

542550
if (where != len) {
543551
// TODO: Replace this dummy drawable with something else
544-
UnknownHtmlSpan unknownHtmlSpan = new UnknownHtmlSpan(rawHtml, context, android.R.drawable.ic_menu_help);
552+
UnknownHtmlSpan unknownHtmlSpan = new UnknownHtmlSpan(rawHtml, context, android.R.drawable.ic_menu_help, onUnknownHtmlClickListener);
545553
text.setSpan(unknownHtmlSpan, where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
546554

547555
UnknownClickableSpan unknownClickableSpan = new UnknownClickableSpan(unknownHtmlSpan);

aztec/src/main/kotlin/org/wordpress/aztec/AztecHtmlSchema.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class AztecHtmlSchema : HTMLSchema() {
88
init {
99
fixIframeElement()
1010
fixLinkElement()
11+
fixBrElement()
1112
}
1213

1314
private fun fixIframeElement() {
@@ -26,4 +27,11 @@ class AztecHtmlSchema : HTMLSchema() {
2627
val index = iframe.atts().getIndex("shape")
2728
iframe.atts().setValue(index, null)
2829
}
30+
31+
private fun fixBrElement() {
32+
val iframe = getElementType("br")
33+
34+
val index = iframe.atts().getIndex("clear")
35+
iframe.atts().setValue(index, null)
36+
}
2937
}

aztec/src/main/kotlin/org/wordpress/aztec/AztecParser.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@ class AztecParser {
3636
internal var hiddenSpans: IntArray = IntArray(0)
3737
internal var spanCursorPosition = -1
3838

39-
fun fromHtml(source: String, onMediaTappedListener: OnMediaTappedListener?, context: Context): Spanned {
39+
fun fromHtml(source: String, onMediaTappedListener: OnMediaTappedListener?,
40+
onUnknownHtmlClickListener: UnknownHtmlSpan.OnUnknownHtmlClickListener?, context: Context): Spanned {
4041
val tidySource = tidy(source)
4142

42-
val spanned = SpannableStringBuilder(Html.fromHtml(tidySource, AztecTagHandler(), onMediaTappedListener, context))
43+
val spanned = SpannableStringBuilder(Html.fromHtml(tidySource, AztecTagHandler(),
44+
onMediaTappedListener, onUnknownHtmlClickListener, context))
4345

4446
addZwjCharToBlockSpans(spanned)
4547
adjustNestedSpanOrder(spanned)
@@ -265,7 +267,7 @@ class AztecParser {
265267

266268
private fun withinUnknown(out: StringBuilder, text: Spanned, start: Int, end: Int, unknownHtmlSpan: UnknownHtmlSpan) {
267269
consumeCursorIfInInput(out, text, start)
268-
out.append(unknownHtmlSpan.getRawHtml())
270+
out.append(unknownHtmlSpan.rawHtml)
269271
consumeCursorIfInInput(out, text, end)
270272
}
271273

aztec/src/main/kotlin/org/wordpress/aztec/AztecTagHandler.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ class AztecTagHandler : Html.TagHandler {
179179
if (start != end) {
180180
output.setSpan(last, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
181181
}
182+
//if block element is empty add newline to it and extend span
183+
else if (start == end && AztecBlockSpan::class.java.isAssignableFrom(kind)) {
184+
output.append("\n")
185+
output.setSpan(last, start, output.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
186+
}
182187
}
183188

184189
companion object {

0 commit comments

Comments
 (0)