Java tutorial
/******************************************************************************* * This file is part of AndFChat. * * AndFChat 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 3 of the License, or * (at your option) any later version. * * AndFChat 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 AndFChat. If not, see <http://www.gnu.org/licenses/>. ******************************************************************************/ package com.andfchat.frontend.activities; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import net.sourcerer.quickaction.ActionItem; import net.sourcerer.quickaction.CheckActionItem; import net.sourcerer.quickaction.PopUpAlignment; import net.sourcerer.quickaction.QuickActionBar; import net.sourcerer.quickaction.QuickActionOnClickListener; import net.sourcerer.quickaction.QuickActionOnOpenListener; import roboguice.RoboGuice; import roboguice.activity.RoboActionBarActivity; import roboguice.inject.InjectView; import roboguice.util.Ln; import android.Manifest; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.graphics.Point; import android.media.MediaScannerConnection; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.support.design.widget.Snackbar; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.text.Html; import android.text.Spannable; import android.text.method.LinkMovementMethod; import android.view.Display; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.PopupWindow; import android.widget.TextView; import com.andfchat.R; import com.andfchat.core.connection.FlistWebSocketConnection; import com.andfchat.core.data.CharacterManager; import com.andfchat.core.data.Chatroom; import com.andfchat.core.data.ChatroomManager; import com.andfchat.core.data.SessionData; import com.andfchat.core.data.history.HistoryManager; import com.andfchat.core.data.messages.AdEntry; import com.andfchat.core.data.messages.ChatEntry; import com.andfchat.core.data.messages.ChatEntryFactory; import com.andfchat.core.util.SmileyReader; import com.andfchat.core.util.Version; import com.andfchat.frontend.application.AndFChatApplication; import com.andfchat.frontend.application.AndFChatNotification; import com.andfchat.frontend.events.AndFChatEventManager; import com.andfchat.frontend.events.ChatroomEventListener; import com.andfchat.frontend.events.ConnectionEventListener; import com.andfchat.frontend.events.MessageEventListener; import com.andfchat.frontend.events.UserEventListener; import com.andfchat.frontend.fragments.ChannelListFragment; import com.andfchat.frontend.fragments.ChatFragment; import com.andfchat.frontend.fragments.ChatInputFragment; import com.andfchat.frontend.fragments.UserListFragment; import com.andfchat.frontend.menu.AboutAction; import com.andfchat.frontend.menu.DisconnectAction; import com.andfchat.frontend.menu.FriendListAction; import com.andfchat.frontend.menu.JoinChannelAction; import com.andfchat.frontend.popup.FListCharSelectionPopup; import com.andfchat.frontend.popup.FListLoginPopup; import com.andfchat.frontend.popup.FListPopupWindow; import com.andfchat.frontend.util.Exporter; import com.andfchat.frontend.util.FlistAlertDialog; import com.google.inject.Inject; import com.readystatesoftware.systembartint.SystemBarTintManager; public class ChatScreen extends RoboActionBarActivity implements ChatroomEventListener, ChatEntryFactory.AdClickListener, ConnectionEventListener { @Inject protected CharacterManager charManager; @Inject protected ChatroomManager chatroomManager; @Inject protected FlistWebSocketConnection connection; @Inject protected SessionData sessionData; @Inject private AndFChatEventManager eventManager; @Inject protected AndFChatNotification notificationManager; @Inject protected HistoryManager historyManager; @Inject protected ChatEntryFactory entryFactory; @Inject protected Context context; @InjectView(R.id.toggleSidebarLeft) private Button toggleSidebarLeft; @InjectView(R.id.toggleSidebarRight) private Button toggleSidebarRight; @InjectView(R.id.chatMessage) private EditText inputText; @InjectView(R.id.sendButton) private Button sendButton; @InjectView(R.id.actionButton) private Button actionButton; @InjectView(R.id.mainframe) private View frame; // Fragments private ChatFragment chatFragment; private UserListFragment userList; private ChannelListFragment channelList; private ChatInputFragment inputFragment; // Display height private int height; private int width; static final int MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 0; private QuickActionBar actionBar; private FListLoginPopup loginPopup; private FListCharSelectionPopup charSelectionPopup; private boolean paused = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTheme(sessionData.getSessionSettings().getTheme()); setContentView(R.layout.activity_chat_screen); AdEntry.setAdClickListener(this); SystemBarTintManager tintManager = new SystemBarTintManager(this); // enable status bar tint tintManager.setStatusBarTintEnabled(true); tintManager.setTintColor(getResources().getColor(R.color.primary_color_dark)); toggleSidebarRight.setSelected(false); eventManager.clear(); eventManager.register((ChatroomEventListener) this); eventManager.register((ConnectionEventListener) this); // Fetch fragments chatFragment = (ChatFragment) getSupportFragmentManager().findFragmentById(R.id.chatFragment); userList = (UserListFragment) getSupportFragmentManager().findFragmentById(R.id.userListFragment); channelList = (ChannelListFragment) getSupportFragmentManager().findFragmentById(R.id.channelListFragment); inputFragment = (ChatInputFragment) getSupportFragmentManager().findFragmentById(R.id.chatInputFragment); // Register fragments eventManager.register((ChatroomEventListener) chatFragment); eventManager.register((MessageEventListener) chatFragment); eventManager.register((ChatroomEventListener) userList); eventManager.register((UserEventListener) userList); eventManager.register(channelList); eventManager.register(inputFragment); // PopUps loginPopup = new FListLoginPopup(); charSelectionPopup = new FListCharSelectionPopup(); loginPopup.setDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { if (sessionData.getTicket() == null) { openLogin(); } } }); charSelectionPopup.setDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { if (!sessionData.isInChat()) { connection.closeConnection(ChatScreen.this); sessionData.setTicket(null); openLogin(); } } }); RoboGuice.injectMembers(this, charSelectionPopup); RoboGuice.injectMembers(this, loginPopup); Display display = getWindowManager().getDefaultDisplay(); Point size = new Point(); display.getSize(size); height = size.y; width = size.x; AndFChatApplication application = (AndFChatApplication) getApplicationContext(); application.setScreenDimension(size); setupActionBar(); } @Override public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { switch (requestCode) { case MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: { // If request is cancelled, the result arrays are empty. if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Snackbar.make(this.findViewById(android.R.id.content), R.string.export_perm_granted, Snackbar.LENGTH_LONG).show(); } else { Snackbar.make(this.findViewById(android.R.id.content), R.string.export_perm_denied, Snackbar.LENGTH_LONG).show(); } return; } } } private void setupActionBar() { actionBar = new QuickActionBar(this, R.layout.qa_dialog_custom); actionBar.setAlignment(PopUpAlignment.BOTTOM); // // Show description // ActionItem showDescription = new ActionItem(getString(R.string.channel_description), ContextCompat.getDrawable(this, R.drawable.ic_description)); showDescription.setQuickActionClickListener(new QuickActionOnClickListener() { @Override public void onClick(ActionItem item, View view) { showDescription(); } }); showDescription.setQuickActionOnOpenListener(new QuickActionOnOpenListener() { @Override public void onOpen(ActionItem item) { Chatroom chat = chatroomManager.getActiveChat(); if (chat.isPrivateChat() || chat.isSystemChat()) { item.setVisibility(View.GONE); } else { item.setVisibility(View.VISIBLE); } } }); actionBar.addActionItem(showDescription); // // Export active chatFragment // ActionItem exportActiveChat = new ActionItem(getString(R.string.export_text), ContextCompat.getDrawable(this, R.drawable.ic_export)); exportActiveChat.setQuickActionClickListener(new QuickActionOnClickListener() { @Override public void onClick(ActionItem item, View view) { exportChat(); } }); exportActiveChat.setQuickActionOnOpenListener(new QuickActionOnOpenListener() { @Override public void onOpen(ActionItem item) { Chatroom chat = chatroomManager.getActiveChat(); item.setEnabled(chat.isSystemChat() == false); } }); actionBar.addActionItem(exportActiveChat); actionButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Chatroom chat = chatroomManager.getActiveChat(); if (!chat.isSystemChat()) { actionBar.show(actionButton); } } }); // // Post Ad // ActionItem postAd = new ActionItem(getString(R.string.post_ad_text), ContextCompat.getDrawable(this, R.drawable.ic_post_ad)); postAd.setQuickActionClickListener(new QuickActionOnClickListener() { @Override public void onClick(ActionItem item, View view) { inputFragment.sendTextAsAd(); } }); postAd.setQuickActionOnOpenListener(new QuickActionOnOpenListener() { @Override public void onOpen(ActionItem item) { Chatroom chat = chatroomManager.getActiveChat(); if (chat.isChannel()) { item.setVisibility(View.VISIBLE); } else { item.setVisibility(View.GONE); } } }); actionBar.addActionItem(postAd); // // Post Ad // ActionItem showProfile = new ActionItem(getString(R.string.show_profile), ContextCompat.getDrawable(this, R.drawable.ic_info)); //was getResources.getDrawable showProfile.setQuickActionClickListener(new QuickActionOnClickListener() { @Override public void onClick(ActionItem item, View view) { Chatroom chat = chatroomManager.getActiveChat(); Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.f-list.net/c/" + chat.getCharacters().get(0).getName())); //was https startActivity(browserIntent); } }); // // Show Profile // showProfile.setQuickActionOnOpenListener(new QuickActionOnOpenListener() { @Override public void onOpen(ActionItem item) { Chatroom chat = chatroomManager.getActiveChat(); if (chat.isPrivateChat()) { item.setVisibility(View.VISIBLE); } else { item.setVisibility(View.GONE); } } }); actionBar.addActionItem(showProfile); // // Leave active chatFragment // final ActionItem leaveActiveChat = new ActionItem(getString(R.string.leave_channel), ContextCompat.getDrawable(this, R.drawable.ic_leave)); leaveActiveChat.setQuickActionClickListener(new QuickActionOnClickListener() { @Override public void onClick(ActionItem item, View view) { leaveActiveChat(); } }); leaveActiveChat.setQuickActionOnOpenListener(new QuickActionOnOpenListener() { @Override public void onOpen(ActionItem item) { Chatroom chat = chatroomManager.getActiveChat(); if (chat.isCloseable()) { item.setVisibility(View.VISIBLE); } else { item.setVisibility(View.GONE); } } }); actionBar.addActionItem(leaveActiveChat); // // Leave active chatFragment // final CheckActionItem showAdTexts = new CheckActionItem(getString(R.string.show_ads), ContextCompat.getDrawable(this, R.drawable.ic_post_ad)); showAdTexts.setQuickActionClickListener(new QuickActionOnClickListener() { @Override public void onClick(ActionItem item, View view) { Chatroom chat = chatroomManager.getActiveChat(); boolean value = !chat.getShowAdText(); chat.setShowAdText(value); // Refresh Chat chatFragment.onEvent(chat, ChatroomEventType.ACTIVE); } }); showAdTexts.setQuickActionOnOpenListener(new QuickActionOnOpenListener() { @Override public void onOpen(ActionItem item) { Chatroom chat = chatroomManager.getActiveChat(); // Show only in channel if (chat.isChannel() && chat.isSystemChat() == false) { item.setVisibility(View.VISIBLE); } else { item.setVisibility(View.GONE); } if (chat.getShowAdText()) { showAdTexts.setSelected(true); } else { showAdTexts.setSelected(false); } } }); actionBar.addActionItem(showAdTexts); // // Leave active chatFragment // TODO Convert to being long-press action, rather than QuickActionBar item // final CheckActionItem showProfilePic = new CheckActionItem(getString(R.string.show_avatar), ContextCompat.getDrawable(this, R.drawable.avatar)); showProfilePic.setQuickActionClickListener(new QuickActionOnClickListener() { @Override public void onClick(ActionItem item, View view) { Chatroom chat = chatroomManager.getActiveChat(); boolean value = !chat.getShowAvatar(); chat.setShowAvatar(value); // Refresh Chat channelList.onEvent(chat, ChatroomEventType.ACTIVE); } }); showProfilePic.setQuickActionOnOpenListener(new QuickActionOnOpenListener() { @Override public void onOpen(ActionItem item) { Chatroom chat = chatroomManager.getActiveChat(); // Show only in channel if (chat.isPrivateChat()) { item.setVisibility(View.VISIBLE); } else { item.setVisibility(View.GONE); } if (chat.getShowAvatar()) { showProfilePic.setSelected(true); } else { showProfilePic.setSelected(false); } } }); actionBar.addActionItem(showProfilePic); } public void leaveActiveChat() { Chatroom activeChat = chatroomManager.getActiveChat(); if (activeChat != null) { connection.leaveChannel(activeChat); } } //TODO Convert to edge swipe public void toggleSidebarRight(View v) { toggleSidebarRight.setSelected(userList.toggleVisibility()); } //TODO Convert to edge swipe public void toggleSidebarLeft(View v) { toggleSidebarLeft.setSelected(!channelList.toggleVisibility()); } public void showDescription() { LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.popup_description, null); int height = (int) (this.height * 0.8f); int width = (int) (this.width * 0.8f); final PopupWindow descriptionPopup = new FListPopupWindow(layout, width, height); descriptionPopup.showAtLocation(chatFragment.getView(), Gravity.CENTER, 0, 0); final TextView descriptionText = (TextView) layout.findViewById(R.id.descriptionText); descriptionText.setText(SmileyReader.addSmileys(this, chatroomManager.getActiveChat().getDescription())); // Enable touching/clicking links in text descriptionText.setMovementMethod(LinkMovementMethod.getInstance()); } @Override public void onEvent(Chatroom chatroom, ChatroomEventType type) { if (type == ChatroomEventType.ACTIVE) { actionButton.setVisibility(View.VISIBLE); if (chatroom.isSystemChat()) { toggleSidebarRight.setVisibility(View.GONE); } else { toggleSidebarRight.setVisibility(View.VISIBLE); if (chatroom.isPrivateChat()) { toggleSidebarRight.setVisibility(View.GONE); } } if (chatroom.isPrivateChat() && chatroom.getRecipient().getStatusMsg() != null) { setChannelTitle(/*chatroom.getName() + " - " + */Html .fromHtml(chatroom.getRecipient().getStatusMsg()).toString()); } else { setChannelTitle(chatroom.getName()); } } } private void setChannelTitle(String name) { this.setTitle(name); } public void exportChat() { int permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE); if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE); } else { String filename = "FListLog-" + chatroomManager.getActiveChat().getName() + "-" + System.currentTimeMillis() + ".txt"; File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File file = new File(path, filename); try { path.mkdirs(); OutputStream os = new FileOutputStream(file); os.write(Exporter.exportText(this, chatroomManager.getActiveChat())); os.close(); ChatEntry entry = entryFactory.getNotation(charManager.findCharacter(CharacterManager.USER_SYSTEM), R.string.exported, new Object[] { filename }); chatroomManager.addMessage(chatroomManager.getActiveChat(), entry); // Tell the media scanner about the new file so that it is // immediately available to the user. MediaScannerConnection.scanFile(this, new String[] { file.toString() }, null, new MediaScannerConnection.OnScanCompletedListener() { @Override public void onScanCompleted(String path, Uri uri) { } }); } catch (IOException e) { Ln.w("ExternalStorage", "Error writing " + file, e); ChatEntry entry = entryFactory.getError(charManager.findCharacter(CharacterManager.USER_SYSTEM), R.string.export_failed); chatroomManager.addMessage(chatroomManager.getActiveChat(), entry); } } } @Override protected void onResume() { super.onResume(); paused = false; sessionData.setIsVisible(true); AdEntry.setAdClickListener(this); // Check Version checkVersion(); // Reload chatFragment if (chatroomManager.getActiveChat() != null) { chatroomManager.setActiveChat(chatroomManager.getActiveChat()); } else { actionButton.setVisibility(View.GONE); } if (!connection.isConnected()) { Ln.d("Is not connected, open login"); openLogin(); } else if (sessionData.isInChat() == false) { Ln.d("Is connected, open selection"); openSelection(); } notificationManager.cancelLedNotification(); notificationManager.updateNotification(0); } private void checkVersion() { Version version = sessionData.getSessionSettings().getVersion(); if (version.isLowerThan("0.2.2")) { Ln.i("Updating to version 0.2.2"); historyManager.clearHistory(true); sessionData.getSessionSettings().setVersion("0.2.2"); } if (version.isLowerThan("0.2.3")) { Ln.i("Updating to version 0.2.3"); historyManager.clearHistory(true); sessionData.getSessionSettings().setVersion("0.2.3"); } if (version.isLowerThan("0.4.0")) { Ln.i("Updating to version 0.4.0"); sessionData.getSessionSettings().setVersion("0.4.0"); } if (version.isLowerThan("0.5.0")) { Ln.i("Updating to version 0.5.0"); sessionData.getSessionSettings().setVersion("0.5.0"); } } @Override protected void onPause() { inputFragment.saveEntry(); super.onPause(); if (connection.isConnected()) { Ln.d("Show notification"); notificationManager.updateNotification(0); } paused = true; } @Override protected void onStop() { Ln.i("onStop"); super.onStop(); sessionData.setIsVisible(false); if (connection.isConnected()) { historyManager.saveHistory(); } } @Override protected void onDestroy() { Ln.i("onDestroy"); notificationManager.cancelAll(); super.onDestroy(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu items for use in the action bar MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.activity_main_screen, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle presses on the action bar items // Do smaller chatFragment height on displayed keyboard the height is determined by display size. switch (item.getItemId()) { case R.id.action_add_chat: JoinChannelAction.open(this, chatFragment.getView()); return true; case R.id.action_open_friendlist: FriendListAction.open(this, chatFragment.getView()); return true; case R.id.action_disconnect: DisconnectAction.disconnect(this); return true; case R.id.action_open_settings: startActivity(new Intent(this, Settings.class)); return true; case R.id.action_about: AboutAction.open(this, chatFragment.getView()); return true; case R.id.action_exit: onQuit(); return true; default: return super.onOptionsItemSelected(item); } } /** * Hides the soft keyboard if user is touching anywhere else. */ @Override public boolean dispatchTouchEvent(MotionEvent event) { View view = getCurrentFocus(); boolean ret = super.dispatchTouchEvent(event); if (view instanceof EditText) { View w = getCurrentFocus(); int scrcoords[] = new int[2]; w.getLocationOnScreen(scrcoords); float x = event.getRawX() + w.getLeft() - scrcoords[0]; float y = event.getRawY() + w.getTop() - scrcoords[1]; if (event.getAction() == MotionEvent.ACTION_UP && (x < w.getLeft() || x >= w.getRight() || y < w.getTop() || y > w.getBottom())) { inputFragment.hideKeyboard(); inputFragment.saveEntry(); } } return ret; } public void onQuit() { FlistAlertDialog dialog = new FlistAlertDialog(this, getResources().getString(R.string.question_back)) { @Override public void onYes() { connection.closeConnection(ChatScreen.this); finish(); } @Override public void onNo() { } }; dialog.show(); } @Override public void openAd(Spannable text) { LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View layout = inflater.inflate(R.layout.popup_description, null); int height = (int) (this.height * 0.8f); int width = (int) (this.width * 0.8f); final PopupWindow descriptionPopup = new FListPopupWindow(layout, width, height); descriptionPopup.showAtLocation(frame, Gravity.CENTER, 0, 0); final TextView descriptionText = (TextView) layout.findViewById(R.id.descriptionText); descriptionText.setText(text); // Enable touching/clicking links in text descriptionText.setMovementMethod(LinkMovementMethod.getInstance()); } public void openLogin() { if (paused) { return; } if (sessionData.getTicket() == null) { if (!loginPopup.isShowing()) { loginPopup.show(getFragmentManager(), "login_fragment"); } } else { connection.connect(true); Runnable runnable = new Runnable() { @Override public void run() { if (connection.isConnected()) { openSelection(); } else { sessionData.setTicket(null); openLogin(); } } }; new Handler(Looper.getMainLooper()).postDelayed(runnable, 1000); } } public void openSelection() { if (!charSelectionPopup.isShowing()) { charSelectionPopup.show(getFragmentManager(), "select_fragment"); } } @Override public void onBackPressed() { FlistAlertDialog dialog = new FlistAlertDialog(this, getString(R.string.question_back)) { @Override public void onYes() { ChatScreen.super.onBackPressed(); } @Override public void onNo() { } }; dialog.show(); } @Override public void onEvent(ConnectionEventType type) { if (type == ConnectionEventType.CONNECTED) { if (loginPopup.isShowing()) { loginPopup.dismiss(); } openSelection(); } else if (type == ConnectionEventType.CHAR_CONNECTED) { if (charSelectionPopup.isShowing()) { charSelectionPopup.dismiss(); } sessionData.setDisconnectReason(null); } else if (type == ConnectionEventType.DISCONNECTED) { Ln.i("Disconnected, clear interface!"); historyManager.saveHistory(); actionButton.setVisibility(View.GONE); if (connection.isConnected()) { openSelection(); } else { openLogin(); } } } }