package eu.hgross.blaubot.android.views; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; import android.view.View; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.ToggleButton; import org.apache.commons.collections4.queue.CircularFifoQueue; import java.util.ArrayList; import eu.hgross.blaubot.android.R; import eu.hgross.blaubot.core.Blaubot; import eu.hgross.blaubot.admin.AbstractAdminMessage; import eu.hgross.blaubot.admin.RelayAdminMessage; import eu.hgross.blaubot.messaging.IBlaubotAdminMessageListener; import eu.hgross.blaubot.ui.IBlaubotDebugView; /** * Hooks into the admin messages and shows them (oldest first). */ public class AdminMessageView extends LinearLayout implements IBlaubotDebugView { private static final int MAX_MESSAGES_DEFAULT = 30; private static final String NO_MESSAGES_TEXT = "No admin messages received so far"; private Blaubot mBlaubot; private Handler mUiHandler; private CircularFifoQueue<AbstractAdminMessage> mLastMessages; private final Object queueMonitor = new Object(); private int mMaxMessages = MAX_MESSAGES_DEFAULT; private AttributeSet mAttrs; private Context mContext; private boolean mShowRelayMessages = false; private ToggleButton mToggleRelayAdminMessagesButton; public AdminMessageView(Context context) { super(context); initView(context, null); } public AdminMessageView(Context context, AttributeSet attrs) { super(context, attrs); initView(context, attrs); } private void initView(Context context, AttributeSet attrs) { mContext = context; mAttrs = attrs; if(mAttrs != null) { TypedArray a = context.getTheme().obtainStyledAttributes( attrs, R.styleable.AdminMessageView, 0, 0); try { mMaxMessages = a.getInt(R.styleable.AdminMessageView_maxMessages, mMaxMessages); mShowRelayMessages = a.getBoolean(R.styleable.AdminMessageView_showRelayMessages, mShowRelayMessages); } finally { a.recycle(); } } mLastMessages = new CircularFifoQueue<>(mMaxMessages); mUiHandler = new Handler(Looper.getMainLooper()); mToggleRelayAdminMessagesButton = new ToggleButton(getContext(), null); mToggleRelayAdminMessagesButton.setTextOn("Showing RelayMessages"); mToggleRelayAdminMessagesButton.setTextOff("Not showing RelayMessages"); mToggleRelayAdminMessagesButton.setChecked(mShowRelayMessages); mToggleRelayAdminMessagesButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { mShowRelayMessages = isChecked; } }); } private void clear() { if(mBlaubot != null) { mBlaubot.getChannelManager().removeAdminMessageListener(adminMessageListener); mBlaubot = null; } removeAllViews(); initView(mContext, mAttrs); } private void updateUI() { final ArrayList<AbstractAdminMessage> data; synchronized (queueMonitor) { data = new ArrayList<>(mLastMessages); } mUiHandler.post(new Runnable() { @Override public void run() { final int height = getHeight(), width = getWidth(); if(getOrientation() == VERTICAL) { setMinimumHeight(height); } else { setMinimumWidth(width); } removeAllViews(); addView(mToggleRelayAdminMessagesButton); final Drawable iconDrawable = getResources().getDrawable(android.R.drawable.ic_menu_send); int i = 0, size = data.size(); for(AbstractAdminMessage msg : data) { final View view = inflate(getContext(), R.layout.blaubot_adminmessage_view_list_item, null); final TextView msgView = (TextView) view.findViewById(R.id.messageContent); final ImageView icon = (ImageView) view.findViewById(R.id.icon); icon.setImageDrawable(iconDrawable); msgView.setText(msg.toString()); if(i++ == size-1) { view.findViewById(R.id.divider).setVisibility(INVISIBLE); } addView(view); } if(data.isEmpty()) { TextView tv = new TextView(getContext()); tv.setText(NO_MESSAGES_TEXT); addView(tv); } } }); } private IBlaubotAdminMessageListener adminMessageListener = new IBlaubotAdminMessageListener() { @Override public void onAdminMessage(AbstractAdminMessage adminMessage) { if (adminMessage instanceof RelayAdminMessage) { if (!mShowRelayMessages) { return; // skip relay admin messages if wished } } synchronized (queueMonitor) { mLastMessages.add(adminMessage); } updateUI(); } }; /** * Set if RelayAdminMessages should be rendered. * Note that this can cause heavy load on the ui thread. * * @param mShowRelayMessages if true, relay admin messages are rendered */ public void setShowRelayMessages(boolean mShowRelayMessages) { this.mShowRelayMessages = mShowRelayMessages; } /** * Register this view with the given blaubot instance * * @param blaubot * the blaubot instance to connect with */ @Override public void registerBlaubotInstance(Blaubot blaubot) { if (mBlaubot != null) { unregisterBlaubotInstance(); } this.mBlaubot = blaubot; // register listeners blaubot.getChannelManager().addAdminMessageListener(adminMessageListener); // force some updates updateUI(); } @Override public void unregisterBlaubotInstance() { clear(); } }