/* * TwitterController.java * * Copyright (C) 2005-2010 Tommi Laukkanen * http://www.substanceofcode.com * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.substanceofcode.twitter; import com.substanceofcode.infrastructure.Device; import com.substanceofcode.tasks.AbstractTask; import com.substanceofcode.twitter.model.MediaFileSelect; import com.substanceofcode.twitter.model.Status; import com.substanceofcode.twitter.model.User; import com.substanceofcode.twitter.model.UserList; import com.substanceofcode.twitter.services.RefreshService; import com.substanceofcode.twitter.tasks.ToggleFavoriteTask; import com.substanceofcode.twitter.tasks.RequestFriendsTask; import com.substanceofcode.twitter.tasks.RequestListsTask; import com.substanceofcode.twitter.tasks.RequestTimelineTask; import com.substanceofcode.twitter.tasks.SearchTask; import com.substanceofcode.twitter.tasks.SendPhotoTask; import com.substanceofcode.twitter.tasks.SendVideoTask; import com.substanceofcode.twitter.tasks.ToggleFollowingTask; import com.substanceofcode.twitter.tasks.TranslateTask; import com.substanceofcode.twitter.tasks.UpdateStatusTask; import com.substanceofcode.twitter.views.AboutCanvas; import com.substanceofcode.twitter.views.CameraCanvas; import com.substanceofcode.twitter.views.FileBrowserCanvas; import com.substanceofcode.twitter.views.SettingsForm; import com.substanceofcode.twitter.views.MediaCommentForm; import com.substanceofcode.twitter.views.MenuAction; import com.substanceofcode.twitter.views.SearchTextBox; import com.substanceofcode.twitter.views.SplashCanvas; import com.substanceofcode.twitter.views.Theme; import com.substanceofcode.twitter.views.TimelineCanvas; import com.substanceofcode.twitter.views.UpdateStatusTextBox; import com.substanceofcode.twitter.views.WaitCanvas; import com.substanceofcode.twitter.views.menus.ListsMenu; import com.substanceofcode.twitter.views.menus.OpenListMenuAction; import com.substanceofcode.twitter.views.menus.PhotoServicesMenu; import com.substanceofcode.twitter.views.menus.VideoServicesMenu; import com.substanceofcode.utils.Log; import java.io.IOException; import java.util.Calendar; import java.util.Enumeration; import java.util.Vector; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.midlet.MIDlet; import javax.microedition.rms.RecordStoreException; /** * TwitterController controls the application flow. * * @author Tommi Laukkanen (tlaukkanen at gmail dot com) */ public class TwitterController { TwitterMidlet midlet; Display display; TwitterApi api; Settings settings; TimelineCanvas timeline; PhotoService activePhotoService; VideoService activeVideoService; FileBrowserCanvas fileBrowser; boolean tweetsShownOnce = false; Vector publicTimeline; Vector homeTimeline; Vector archiveTimeline; Vector responsesTimeline; Vector directTimeline; Vector friendsStatuses; Vector favouriteTimeline; Vector retweetsOfMeTimeline; private static final int PUBLIC_TIMELINE = 0; private static final int HOME_TIMELINE = 1; private static final int ARCHIVE_TIMELINE = 2; private static final int RESPONSES_TIMELINE = 3; private static final int DIRECT_TIMELINE = 4; private static final int FRIENDS_TIMELINE = 5; private static final int FAVOURITE_TIMELINE = 6; private static final int SEARCH_TIMELINE = 7; private static final int RETWEETS_OF_ME_TIMELINE = 8; int currentTimeline; static TwitterController instance; public static TwitterController getInstance(TwitterMidlet midlet) { if(instance==null) { instance = new TwitterController(midlet); } return instance; } public static TwitterController getInstance() { return instance; } /** * Creates a new instance of TwitterController * @param midlet Application midlet. */ private TwitterController(TwitterMidlet midlet) { try { this.midlet = midlet; this.display = Display.getDisplay(midlet); this.api = new TwitterApi(); this.timeline = new TimelineCanvas(this); settings = Settings.getInstance(midlet); } catch (IOException ex) { ex.printStackTrace(); } catch (RecordStoreException ex) { ex.printStackTrace(); } } public void about() { AboutCanvas canvas = new AboutCanvas(this); display.setCurrent(canvas); } public void addFavoriteStatus(Status favoriteStatus) { if(favouriteTimeline!=null) { favouriteTimeline.addElement(favoriteStatus); } } public void addStatus(Status status) { if(homeTimeline!=null) { homeTimeline.insertElementAt(status, 0); } if(archiveTimeline!=null) { archiveTimeline.insertElementAt(status, 0); } } public void clearTimelines() { setHomeTimeline(null); setPublicTimeline(null); setResponsesTimeline(null); setUserTimeline(null); setDirectTimeline(null); setFriendsStatuses(null); setFavouriteTimeline(null); } public MIDlet getMIDlet() { return midlet; } public Settings getSettings() { return settings; } public void exit() { try { midlet.quit(); } catch(Exception ex) { Log.error("Exit: " + ex.toString()); } } public Displayable getCurrentDisplay() { return display.getCurrent(); } /** Login to Twitter stream */ public void login() { /** Get saved credentials */ String username = settings.getStringProperty(Settings.USERNAME, ""); api.setUsername(username); String password = settings.getStringProperty(Settings.PASSWORD, ""); api.setPassword(password); String token = settings.getStringProperty(Settings.TOKEN, ""); String tokenSecret = settings.getStringProperty(Settings.TOKEN_SECRET, ""); api.bypassAuthorization(token, tokenSecret); boolean loadTweets = settings.getBooleanProperty(Settings.LOAD_ON_STARTUP, false); /** Login */ login(username, password, loadTweets); } /** * Login to twitter. * @param username Username for Twitter * @param password Password for Twitter */ public void login(String username, String password, boolean loadTweets) { api.setUsername(username); api.setPassword(password); /** Set saved theme */ int theme = settings.getIntProperty(Settings.THEME, 0); Theme.setTheme(theme); /** Start refresh service */ boolean refresh = settings.getBooleanProperty(Settings.REFRESH, false); RefreshService refreshService = RefreshService.getInstance(); if(refresh) { refreshService.activate(); } else { refreshService.deactivate(); } if(loadTweets) { api.authorize(); showHomeTimeline( false ); } else { showEmptyTimeline(); } } public void commentMedia(byte[] media, String filename) { MediaCommentForm commentForm = new MediaCommentForm(media, filename); display.setCurrent(commentForm); } public void minimize() { display.setCurrent(timeline); display.setCurrent(null); } public void setPhotoService(PhotoService service) { this.activePhotoService = service; this.activeVideoService = null; } public void setVideoService(VideoService service) { this.activeVideoService = service; this.activePhotoService = null; } public void showMediaService(byte[] mediaData, boolean isPhoto, String filename) { if(isPhoto) { PhotoServicesMenu servicesMenu = new PhotoServicesMenu(mediaData, filename); display.setCurrent(servicesMenu); } else { VideoServicesMenu servicesMenu = new VideoServicesMenu(mediaData, filename); display.setCurrent(servicesMenu); } } public void showVideoBrowser() { if(fileBrowser==null) { fileBrowser = new FileBrowserCanvas(new MediaFileSelect(false)); fileBrowser.showRoots(); } fileBrowser.resetToLastFolder(); display.setCurrent(fileBrowser); } public void toggleFavorite(Status selectedStatus) { ToggleFavoriteTask task = new ToggleFavoriteTask(this, api, selectedStatus); WaitCanvas wait = new WaitCanvas(this, task); if(selectedStatus.isFavorite()) { wait.setWaitText("Unfavorite status..."); } else { wait.setWaitText("Marking as favorite..."); } display.setCurrent(wait); } public void sendMedia(String comment, String filename, byte[] media) { String username = api.getUsername(); String password = api.getPassword(); AbstractTask task = null; if(activePhotoService!=null) { task = new SendPhotoTask(media, comment, username, password, activePhotoService, filename); } else { task = new SendVideoTask(media, comment, username, password, activeVideoService, filename); } WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Sending..."); display.setCurrent(wait); } public void setPublicTimeline(Vector publicTimeline) { this.publicTimeline = publicTimeline; } public void setResponsesTimeline(Vector responsesTimeline) { this.responsesTimeline = responsesTimeline; } public void setUserTimeline(Vector archiveTimeline) { this.archiveTimeline = archiveTimeline; } public void setDirectTimeline(Vector directTimeline) { this.directTimeline = directTimeline; } public void setFriendsStatuses(Vector friendStatuses) { this.friendsStatuses = friendStatuses; } public void showCamera() { CameraCanvas camCanvas = new CameraCanvas(); display.setCurrent(camCanvas); camCanvas.start(); } public void showDirectMessages() { currentTimeline = DIRECT_TIMELINE; timeline.showDrawNextPageLink(false); if(directTimeline==null) { RequestTimelineTask task = new RequestTimelineTask( this, api, RequestTimelineTask.FEED_DIRECT, 1); WaitCanvas wait = new WaitCanvas(this, task); display.setCurrent(wait); } else { timeline.setTimeline(directTimeline); display.setCurrent(timeline); } } public void showError(String string) { Alert alert = new Alert("Error"); alert.setString(string); alert.setTimeout(Alert.FOREVER); display.setCurrent(alert, timeline); } public void showInfo(String info) { Alert alert = new Alert("Info"); alert.setString(info); alert.setTimeout(Alert.FOREVER); display.setCurrent(alert, timeline); } public void showPhotoBrowser() { try { if(fileBrowser==null) { fileBrowser = new FileBrowserCanvas(new MediaFileSelect(true)); fileBrowser.showRoots(); } fileBrowser.resetToLastFolder(); display.setCurrent(fileBrowser); } catch(Exception ex) { showError("Can't show photo browser due to an error. Your phone probably doesn't support File Connection API calls. Err: " + ex.getMessage() ); } } /** Show friends */ public void showFriends() { currentTimeline = FRIENDS_TIMELINE; timeline.showDrawNextPageLink(false); if(friendsStatuses==null) { RequestFriendsTask task = new RequestFriendsTask(this, api); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading friends"); display.setCurrent(wait); } else { timeline.setTimeline(friendsStatuses); display.setCurrent(timeline); } } /** Show friends */ public void showFriends(Vector friends) { currentTimeline = FRIENDS_TIMELINE; timeline.showDrawNextPageLink(false); String state = ""; state = "setting friends timeline"; timeline.setTimeline(friends); state = "showing timeline"; display.setCurrent(timeline); } public void showPublicTimeline() { currentTimeline = PUBLIC_TIMELINE; timeline.showDrawNextPageLink(false); if(publicTimeline==null) { RequestTimelineTask task = new RequestTimelineTask( this, api, RequestTimelineTask.FEED_PUBLIC, 1); WaitCanvas wait = new WaitCanvas(this, task); display.setCurrent(wait); } else { timeline.setTimeline(publicTimeline); display.setCurrent(timeline); } } public void showResponsesTimeline() { currentTimeline = RESPONSES_TIMELINE; timeline.showDrawNextPageLink(false); if(responsesTimeline==null) { RequestTimelineTask task = new RequestTimelineTask( this, api, RequestTimelineTask.FEED_RESPONSES, 1); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading responses..."); display.setCurrent(wait); } else { timeline.setTimeline(responsesTimeline); display.setCurrent(timeline); } } public void showRetweetsOfMeTimeline(boolean nextPage) { currentTimeline = RETWEETS_OF_ME_TIMELINE; timeline.showDrawNextPageLink(true); if( retweetsOfMeTimeline==null || nextPage) { timeline.selectRetweetsOfMeTab(!nextPage); int page = 1; if(nextPage) { if(retweetsOfMeTimeline!=null) { int pages = retweetsOfMeTimeline.size() / 20; page += pages; } } RequestTimelineTask task = new RequestTimelineTask( this, api, RequestTimelineTask.FEED_RETWEETS_OF_ME, page); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading retweets of you..."); if(display.getCurrent()!=null || tweetsShownOnce==false) { display.setCurrent(wait); } } else { timeline.setTimeline( homeTimeline ); timeline.resetScrolling(); if(display.getCurrent()!=null || tweetsShownOnce==false) { display.setCurrent( timeline ); } tweetsShownOnce = true; } } /** Show status updating view. */ public void showStatusView(String prefix) { UpdateStatusTextBox statusView = new UpdateStatusTextBox(this, prefix); display.setCurrent(statusView); } public void toggleFollow(Status status) { ToggleFollowingTask task = new ToggleFollowingTask(this, api, status); WaitCanvas wait = new WaitCanvas(this, task); String waitText = ""; if(status.isFollowing()) { waitText = "Unfollow"; } else { waitText = "Follow"; } wait.setWaitText(waitText + " " + status.getScreenName() + "..."); display.setCurrent(wait); } /** * Update Twitter status. * @param status New status */ public void updateStatus(String status) { UpdateStatusTask task = new UpdateStatusTask( this, api, status ); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Updating status..."); display.setCurrent(wait); } public void useArchiveTimeline() { timeline.setTimeline(archiveTimeline); } public void useResponsesTimeline() { timeline.setTimeline(responsesTimeline); } public void showArchiveTimeline(boolean showNextAvailablePage) { currentTimeline = ARCHIVE_TIMELINE; timeline.showDrawNextPageLink(false); if(archiveTimeline==null) { RequestTimelineTask task = new RequestTimelineTask( this, api, RequestTimelineTask.FEED_ARCHIVE, 1); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading tweets..."); display.setCurrent(wait); } else { timeline.setTimeline(archiveTimeline); display.setCurrent(timeline); } } /** * Set friends time line entries. * @param friendsTimeline */ public void setHomeTimeline(Vector timeline) { this.homeTimeline = timeline; } public void setFavouriteTimeline(Vector timeline) { this.favouriteTimeline = timeline; } /** Show login form */ public void showSettingsForm() { SettingsForm settingsForm = new SettingsForm( this ); display.setCurrent( settingsForm ); } /** * Check if application is minimized * @return true if minimized */ public boolean isMinimized() { if(display.getCurrent()==null) { return true; } else { return false; } } public void showHomeTimeline(boolean nextPage) { currentTimeline = HOME_TIMELINE; timeline.showDrawNextPageLink(true); if( homeTimeline==null || nextPage) { timeline.selectHomeTab( !nextPage ); int page = 1; if(nextPage) { if(homeTimeline!=null) { int pages = homeTimeline.size() / 20; page += pages; } } RequestTimelineTask task = new RequestTimelineTask( this, api, RequestTimelineTask.FEED_HOME, page); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading your timeline..."); if(display.getCurrent()!=null || tweetsShownOnce==false) { display.setCurrent(wait); } } else { timeline.setTimeline( homeTimeline ); timeline.resetScrolling(); if(display.getCurrent()!=null || tweetsShownOnce==false) { display.setCurrent( timeline ); } tweetsShownOnce = true; } } public void showFavouriteTimeline() { currentTimeline = FAVOURITE_TIMELINE; timeline.showDrawNextPageLink(false); if( favouriteTimeline==null) { RequestTimelineTask task = new RequestTimelineTask( this, api, RequestTimelineTask.FEED_FAVOURITE, 1); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading your timeline..."); display.setCurrent(wait); } else { timeline.setTimeline( favouriteTimeline ); timeline.resetScrolling(); display.setCurrent( timeline ); } } public void showTimeline(Vector timelineFeed) { if(timelineFeed==null || timelineFeed.isEmpty()) { showError("No statuses to display"); } else { timeline.setTimeline( timelineFeed ); /** Don't show if we are in minimized mode */ if(display.getCurrent()!=null) { display.setCurrent( timeline ); } } } /** Show current timeline */ public void showTimeline() { timeline.resetScrolling(); timeline.resetMenus(); display.setCurrent(timeline); } /** Show splash screen */ public void showSplash() { SplashCanvas splash = new SplashCanvas(this); display.setCurrent(splash); } /** Show empty timeline view */ private void showEmptyTimeline() { Vector empty = new Vector(); timeline.showDrawNextPageLink(false); empty.addElement( new Status( "Twim", "Select what tweets you'd like to see", Calendar.getInstance().getTime(), "0") ); if(Device.isTouch()) { timeline.resetMenuTab(); } timeline.setTimeline(empty); display.setCurrent(timeline); } /** * Remove specified status from favorite timeline * @param unfavoriteStatus Status that have been unfavorited. */ public void removeFavoriteStatus(Status unfavoriteStatus) { Enumeration enu = favouriteTimeline.elements(); while(enu.hasMoreElements()) { Status stat = (Status) enu.nextElement(); if(stat.getId().equals(unfavoriteStatus.getId())) { favouriteTimeline.removeElement(stat); } } } public void showSearchForm() { SearchTextBox searchBox = new SearchTextBox(); display.setCurrent(searchBox); } public void search(String query) { timeline.showDrawNextPageLink(true); currentTimeline = SEARCH_TIMELINE; SearchTask task = new SearchTask(query, api); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Searching..."); display.setCurrent(wait); } public void searchNextPage() { SearchTask task = new SearchTask(api); SearchTask.turnPage(); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading next page..."); display.setCurrent(wait); } public void showTweets(Vector results, String string) { timeline.setTimeline(results); timeline.resetScrolling(); timeline.resetMenuTab(); display.setCurrent(timeline); } public void showPreviousTimeline() { timeline.resetMenus(); display.setCurrent(timeline); } /** * Get recent status items. * @return recent status items in vector */ public Vector getRecentStatuses() { return homeTimeline; } public void vibrate(int milliSeconds) { display.vibrate(milliSeconds); } /** * Can we make an auto-refresh? * @return true if we can */ public boolean canAutorefresh() { boolean timelineIsShown = (display.getCurrent()==timeline); if(timelineIsShown || isMinimized()) { return true; } else { return false; } } /** * Play info sound. */ public void playInfoSound() { display.vibrate(500); AlertType.INFO.playSound(display); } public void translateToEnglish(Status status) { TranslateTask task = new TranslateTask( status ); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Translating..."); display.setCurrent(wait); } public void showSingleStatus(Status stat) { Vector statuses = new Vector(1); statuses.addElement(stat); timeline.setTimeline(statuses); timeline.resetScrolling(); display.setCurrent(timeline); } public void loadNextPage() { switch(currentTimeline) { case(PUBLIC_TIMELINE): break; case(HOME_TIMELINE): showHomeTimeline(true); break; case(ARCHIVE_TIMELINE): break; case(RESPONSES_TIMELINE): break; case(DIRECT_TIMELINE): break; case(FRIENDS_TIMELINE): break; case(FAVOURITE_TIMELINE): break; case(SEARCH_TIMELINE): searchNextPage(); break; default: break; } } public void addToHomeTimeline(Vector timeline) { addToTimeline(homeTimeline, timeline); } private void addToTimeline(Vector original, Vector added) { if(added!=null) { Enumeration en = added.elements(); while(en.hasMoreElements()) { Status stat = (Status)en.nextElement(); original.addElement( stat ); } } } public Vector getHomeTimeline() { return homeTimeline; } public void setRetweetsOfMeTimeline(Vector timeline) { this.retweetsOfMeTimeline = timeline; } public Vector getRetweetsOfMeTimeline() { return retweetsOfMeTimeline; } /** Show user lists */ public void showLists(Vector lists) { MenuAction[] actions = new MenuAction[ lists.size() ]; String[] names = new String[ lists.size() ]; Enumeration elements = lists.elements(); int i=0; while(elements.hasMoreElements()) { UserList list = (UserList)elements.nextElement(); actions[i] = new OpenListMenuAction(list); names[i] = list.getName(); i++; } ListsMenu listsMenu = new ListsMenu( names, actions ); display.setCurrent(listsMenu); } /** Start loading user lists */ public void showLists() { RequestListsTask task = new RequestListsTask(this, this.api); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading your lists..."); display.setCurrent(wait); } /** Show selected user list content */ public void showList(UserList userList) { RequestTimelineTask task = new RequestTimelineTask( this, this.api, userList.getId()); WaitCanvas wait = new WaitCanvas(this, task); wait.setWaitText("Loading list of " + userList.getName()); display.setCurrent(wait); } /** Resets authentication token and secret */ public void resetAuthenticationToken() { api.resetToken(); showInfo("Authentication token was reset."); } }