/*
* Copyright (C) 2015 AChep@xda <artemchep@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package com.achep.acdisplay.ui.widgets.notification;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.UnderlineSpan;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.achep.acdisplay.R;
import com.achep.base.tests.Check;
import java.util.Arrays;
/**
* @author Artem Chepurnoy
* @since 3.1
*/
public class NotificationMessages extends LinearLayout {
private CharSequence[] mMessages;
private boolean mHighlightMessages;
private int mMaxLines;
public NotificationMessages(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NotificationMessages(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationMessages);
setMaxLines(a.getInt(R.styleable.NotificationMessages_maxLines, 6));
setHighlightMessagesEnabled(a.getBoolean(R.styleable.NotificationMessages_highlightMessages, true));
a.recycle();
}
public void setMaxLines(int maxLines) {
mMaxLines = maxLines;
updateMessages();
}
public void setHighlightMessagesEnabled(boolean enabled) {
mHighlightMessages = enabled;
updateMessages();
}
protected void updateMessages() {
if (mMessages != null) setMessages(mMessages);
}
/**
* @param messages an array of non-empty messages.
*/
public void setMessages(final @Nullable CharSequence[] messages) {
mMessages = messages;
if (messages == null) {
// Free messages' container.
removeAllViews();
return;
}
int freeLines = mMaxLines;
final int length = messages.length;
final int viewCount = Math.min(length, freeLines);
final int[] viewMaxLines = new int[length];
if (freeLines > length) { // We can reserve more than one line per message
// Initial setup.
Arrays.fill(viewMaxLines, 1);
freeLines -= length;
// Build list of lengths, so we don't have
// to recalculate it every time.
int[] msgLengths = new int[length];
for (int i = 0; i < length; i++) {
assert messages[i] != null;
msgLengths[i] = messages[i].length();
}
while (freeLines > 0) {
int pos = 0;
float a = 0;
for (int i = 0; i < length; i++) {
final float k = (float) msgLengths[i] / viewMaxLines[i];
if (k > a) {
a = k;
pos = i;
}
}
viewMaxLines[pos]++;
freeLines--;
}
} else {
// Show first messages.
for (int i = 0; freeLines > 0; freeLines--, i++) {
viewMaxLines[i] = 1;
}
}
View[] views = new View[viewCount];
// Find available views.
int childCount = getChildCount();
for (int i = Math.min(childCount, viewCount) - 1; i >= 0; i--) {
views[i] = getChildAt(i);
}
// Remove redundant views.
for (int i = childCount - 1; i >= viewCount; i--) {
removeViewAt(i);
}
boolean highlightFirstLetter = mHighlightMessages && viewCount > 1;
LayoutInflater inflater = null;
for (int i = 0; i < viewCount; i++) {
View root = views[i];
if (root == null) {
// Initialize layout inflater only when we really need it.
if (inflater == null) {
inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
assert inflater != null;
}
root = inflater.inflate(
getMessageLayoutResource(),
this, false);
// FIXME: ?
// We need to keep all IDs unique to make
// TransitionManager#beginDelayedTransition(ViewGroup)
// work correctly!
root.setId(getChildCount() + 1);
addView(root);
}
Check.getInstance().isTrue(messages[i].length() != 0);
final CharSequence text;
final char char_ = messages[i].charAt(0);
if (highlightFirstLetter && (Character.isLetter(char_) || Character.isDigit(char_))) {
SpannableString spannable = new SpannableString(messages[i]);
spannable.setSpan(new UnderlineSpan(), 0, 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
text = spannable;
} else {
text = messages[i];
}
// Get message view and apply the content.
TextView textView = root instanceof TextView
? (TextView) root
: (TextView) root.findViewById(android.R.id.message);
textView.setMaxLines(viewMaxLines[i]);
textView.setText(text);
}
}
@LayoutRes
protected int getMessageLayoutResource() {
return R.layout.notification_message;
}
}