Compare commits

...

470 Commits
v0.5 ... master

Author SHA1 Message Date
Travis Burtrum ebbdc383ec Set SNI hostname if we can for TLS connections 2015-07-24 23:47:48 -04:00
Sebastian Kaspari 2282784df2 Change support channel network to Freenode. Fixes #163. 2015-05-12 20:55:26 +02:00
Sebastian Kaspari d9b17bc4a1 Travis: Use channel on freenode network. 2015-05-12 18:22:02 +02:00
Sebastian Kaspari aea85d6cd6 ConversationFragment: Remove unused REQUEST_CODE_SPEECH. 2015-04-24 22:20:03 +02:00
Sebastian Kaspari 7f680f1282 Migrate MainActivity to use AppCompatActivity. 2015-04-24 21:51:55 +02:00
Sebastian Kaspari 19c9541307 Update support library dependency to version 22.1.1. 2015-04-24 21:39:52 +02:00
Sebastian Kaspari fd6f2d219f Remove ViewPagerIndicator from README. 2015-04-24 21:31:15 +02:00
Sebastian Kaspari c4f3fd1cd8 Add header to navigation drawer. 2015-04-06 21:42:06 +02:00
Sebastian Kaspari 1e0ac76c15 Speed up fragment transaction animation. 2015-04-06 21:41:45 +02:00
Sebastian Kaspari 408dfdb2e3 OverviewFragment: Add ripple effect to server card and menu button. 2015-04-06 21:27:52 +02:00
Sebastian Kaspari cd759757fb MainActivity: Initialize toolbar before (possibly) re-creating fragments. 2015-04-06 00:16:07 +02:00
Sebastian Kaspari 0cf49a6cd3 AddServerActivity: Add "Done / Discard" buttons to toolbar. 2015-04-06 00:01:39 +02:00
Sebastian Kaspari 948ef762cd Use notification icon that matches the guidelines. 2015-04-06 00:00:24 +02:00
Sebastian Kaspari 3f4b2f2de3 OverviewFragment: Use connected/disconnected icons from navigation drawer. 2015-04-05 22:26:05 +02:00
Sebastian Kaspari 91c0d23ac2 Add icons to the navigation drawer. 2015-04-05 22:07:42 +02:00
Sebastian Kaspari 29bdca690f AboutActivity / JoinActivity: Use Material dialog theme. 2015-04-05 14:17:03 +02:00
Sebastian Kaspari dec2c2cc1d Manifest: Remove ConversationActivity and SettingsActivity (They are now fragments). 2015-04-05 14:13:34 +02:00
Sebastian Kaspari 5891d90b24 AboutActivity: Read version name from package manager. 2015-04-05 14:10:31 +02:00
Sebastian Kaspari ff7cf2656b Travis: Fix typo in dependency. 2015-04-04 22:43:24 +02:00
Sebastian Kaspari 2f17919e2e Build gradle: Add maven central as fallback if jcenter is down (like now..) 2015-04-04 22:26:06 +02:00
Sebastian Kaspari 408d4ee80e MainActivity: Add animation when switching fragments. 2015-04-04 22:23:39 +02:00
Sebastian Kaspari 6d843abbac ConversationFragment: Enable options menu. 2015-04-04 22:11:33 +02:00
Sebastian Kaspari 92ae35c7b0 Travis: Set up IRC notifications. 2015-04-04 21:53:12 +02:00
Sebastian Kaspari 63e6a70314 Modify indicator: Larger text size, thinner indicator, no shadow. 2015-04-04 21:48:01 +02:00
Sebastian Kaspari 0de229c130 ConversationFragment: Move indicator from layout to toolbar (replacing toolbar title). 2015-04-04 21:37:18 +02:00
Sebastian Kaspari 3e4f8f57bd Rename: ApplicationController -> YaaicApplication. 2015-04-04 14:02:28 +02:00
Sebastian Kaspari 6ee5ed0eff Used shared interface for fragments accessing main activity. Set title of activity from fragments. 2015-04-04 14:01:57 +02:00
Sebastian Kaspari fc6516e1d3 Add "overview" menu item to navigation drawer. 2015-04-04 13:06:14 +02:00
Sebastian Kaspari b374f2972d Refactor ConversationActivity to ConversationFragment.
This commit also removes the speech recognition setting. This feature is part of most modern keyboards nowadays.
2015-04-04 12:55:24 +02:00
Sebastian Kaspari 06591a9b4e Remove now unused SettingsActivity. 2015-04-04 10:27:54 +02:00
Sebastian Kaspari c5dd873e9d Refactor settings from activity to fragment implementation. 2015-03-29 16:16:32 +02:00
Sebastian Kaspari bb8cd1a4de Add servers to drawer. 2015-03-29 14:21:16 +02:00
Sebastian Kaspari 690e9442f3 Move loading of servers from Service to Application object. 2015-03-28 10:50:56 +01:00
Sebastian Kaspari 4aca69e765 Link settings and about activity from navigation drawer. 2015-03-26 18:31:38 +01:00
Sebastian Kaspari 0e0b2bb199 Refactor AddServerActivity to use Toolbar API. 2015-03-25 22:23:56 +01:00
Sebastian Kaspari b1fe1b09a0 ConversationActivity: Cardify UI. Add send button. Trigger nick completion on send button long press. 2015-03-24 22:19:25 +01:00
Sebastian Kaspari 0a539c3a04 Disable aborting builds on lint warnings.
Unfortunately a warning inside of appcompat prevents us from enabling this option.
2015-03-23 22:03:26 +01:00
Sebastian Kaspari 396d6cec0a Remove ViewPagerIndicator dependency. 2015-03-22 21:43:49 +01:00
Sebastian Kaspari 33560b4913 MainActivity: Whoops. Remove space in package name. 2015-03-22 21:40:41 +01:00
Sebastian Kaspari 74ae710f22 Introduce NavigationDrawer, Migrate to AppCompatTheme, Replace ActionBar with Toolbar. 2015-03-22 21:36:42 +01:00
Sebastian Kaspari deaf1c4679 Move control hightlight color from theme to colors.xml. 2015-03-22 18:24:21 +01:00
Sebastian Kaspari 3b66320fb0 Replace ConversationIndicator with SlidingTabLayout implementation - #132 2015-03-21 22:18:03 +01:00
Sebastian Kaspari 521d1ead14 IRCService: Replace ServersActivity and old icon references. 2015-03-21 12:20:48 +01:00
Sebastian Kaspari 465e4e407e Remove old icon. 2015-03-21 12:09:11 +01:00
Sebastian Kaspari 2c78483c64 Refactoring ServersActivity to new (more "Material") OverviewFragment.
The new launch activity is MainActivity. The other activities will mostly become fragments.
2015-03-21 12:08:37 +01:00
Sebastian Kaspari 9ed0b8c001 New app icon. 2015-03-20 20:19:27 +01:00
Sebastian Kaspari 5e304a2d98 ServersActivity: Remove "Add server" icon from list. 2015-03-18 08:48:51 +01:00
Sebastian Kaspari 54b8f01e32 ConversationsActivity: Hide actions in overflow menu. 2015-03-18 08:43:38 +01:00
Sebastian Kaspari 86e6f49f8b Let travis know about build tools 22. 2015-03-18 08:42:24 +01:00
Sebastian Kaspari 0a42cb5352 Use build tools version 22. 2015-03-18 08:26:07 +01:00
Sebastian Kaspari 330239c093 Add Floating Action Button (FAB) resources. 2015-03-18 08:23:19 +01:00
Sebastian Kaspari 0256c28391 ServersActivity: Move actions to overflow menu. 2015-03-17 23:43:18 +01:00
Sebastian Kaspari 7abdd48094 Use Material theme for dialogs. 2015-03-17 23:42:08 +01:00
Sebastian Kaspari 4c26ac0586 Theme: First version of theme palette. 2015-03-17 23:42:08 +01:00
Sebastian Kaspari 7cd59283eb Update version name to "2.0". 2015-03-17 23:42:08 +01:00
Sebastian Kaspari 8da30cc425 Update CHANGELOG (Yaaic 1.1). 2015-03-17 23:42:08 +01:00
Sebastian Kaspari a1147a60f2 Yaaic 1.1 Release. 2015-03-17 23:42:08 +01:00
Sebastian Kaspari b316f2e9eb Move things around in README.md 2015-03-14 09:02:11 +01:00
Sebastian Kaspari 5d9ba0d119 Update README.md (Using Markdown formatting) 2015-03-14 09:00:29 +01:00
Sebastian Kaspari 8fc20b46a4 Use Markdown formatting in README: README -> README.md 2015-03-14 08:48:33 +01:00
Sebastian Kaspari c8ecda3436 Update README to reflect the latest changes. 2015-03-14 08:46:54 +01:00
Sebastian Kaspari ab590458e3 Travis: Use Android 22 API. 2015-03-14 00:15:37 +01:00
Sebastian Kaspari e2200d9e64 Fix keyboard not showing when text input is pressed. Fixes #156. 2015-03-14 00:08:10 +01:00
Sebastian Kaspari 7cf957d0b2 Fix lint errors. 2015-03-14 00:02:11 +01:00
Sebastian Kaspari d6f1cd4c41 Remove outdated translations. 2015-03-14 00:01:17 +01:00
Sebastian Kaspari 8fe8b9669a Rename: travis.yml -> .travis.yml. 2015-03-13 23:46:34 +01:00
Sebastian Kaspari f564245ee8 Add configuration file for Travis-CI. 2015-03-13 23:44:19 +01:00
Sebastian Kaspari 90055e839c Remove ActionBarSherlock dependency and refactor code to use native ActionBar. 2015-03-13 23:42:47 +01:00
Sebastian Kaspari c813a4a79e Remove outdated Holo TextView style. 2015-03-13 23:27:50 +01:00
Sebastian Kaspari c6b9c700f0 Use Theme.Material as base theme. 2015-03-13 23:25:03 +01:00
Sebastian Kaspari 4b1642bce1 Update support library to version 22. 2015-03-13 23:20:18 +01:00
Sebastian Kaspari 6c93aaef62 Set version to 1.1. 2015-03-13 23:17:28 +01:00
Sebastian Kaspari 175254e652 Modify project to build using gradle. 2015-03-13 17:05:53 +01:00
Ricky Elrod 170f632c07 Add an option to show seconds in the timestamp 2013-03-25 11:07:59 +01:00
Sebastian Kaspari 8858b362fe README: It's 2013! 2013-01-29 21:39:31 +01:00
Sebastian Kaspari a39a4259ea Add setting to debug IRC traffic. Refs #91.
After this setting has been enabled all IRC traffic will be written
to the verbose log (only for new connections).
2013-01-29 21:35:48 +01:00
Sebastian Kaspari f9ef1c65ec Remove eclipse settings files. 2013-01-29 21:32:47 +01:00
Sebastian Kaspari 4d49e5e106 Drop GoogleTV support again (Remove android.hardware.touchscreen=false). 2013-01-22 21:43:17 +01:00
Sebastian Kaspari b479ac55dc MessageListView: Background is now in drawable folder. (Funny that this worked at all). 2013-01-22 21:35:12 +01:00
Sebastian Kaspari f3239d9492 Update language files. 2013-01-22 21:34:35 +01:00
Sebastian Kaspari cdcc3c1eb3 Settings keys/values are not translatable (settings.xml). Refs #102. 2013-01-22 21:17:35 +01:00
Sebastian Kaspari ae131d8acd Charsets are not translatable. Refs #102. 2013-01-22 21:15:22 +01:00
Sebastian Kaspari 936a747d41 Move conversation.xml from layout folder to drawable folder (This is a drawable and no layout). Refs #102. 2013-01-22 21:13:44 +01:00
Sebastian Kaspari fd3e9f3f04 arrays.xml: Move strings to strings.xml and mark non-translatable values. Refs #102. 2013-01-22 21:11:43 +01:00
Sebastian Kaspari e931087172 Manifest: Allow backup of app. 2013-01-21 21:40:03 +01:00
Sebastian Kaspari 214faa06b6 Build against platform version 17 (And use maven plugin 3.5.0). 2013-01-21 21:39:46 +01:00
Sebastian Kaspari ead068e78e Strings in application.xml are not translatable. Refs #102. 2013-01-21 21:34:30 +01:00
Sebastian Kaspari 48b12bff40 Update copyright line (2009-2013). 2013-01-21 21:32:43 +01:00
Sebastian Kaspari 98076c1d24 New default settings. Fixes #116.
* Colorize Nicknames: On
* (mIRC) Colors: On
* Show message colors: On
* Show graphical smilies: On
* Autocorrect input: On
2013-01-21 21:25:29 +01:00
Sebastian Kaspari c1f2648628 Allow copy&paste of text in ConversationActivity. Fixes #118. 2013-01-21 21:21:49 +01:00
Sebastian Kaspari 81b7fe798c MessageListView: Set transcript mode to normal (Only automatically scroll if the last item is visible). Fixes #119. 2013-01-21 21:15:22 +01:00
Sebastian Kaspari dbdc731965 Update support library to version 11. 2013-01-21 21:11:09 +01:00
Sebastian Kaspari e05b15731c Theme: Remove absForceOverflow property. Not supported anymore in ActionBarSherlock 4.2. Fixes #129. 2013-01-21 21:10:47 +01:00
Sebastian Kaspari b9b1468157 Update ActionBarSherlock dependency to version 4.2. 2013-01-21 20:58:59 +01:00
Sebastian Kaspari 09091c229a Update test project classpath to include new robotium version 3.5.1 2012-11-06 21:09:36 +01:00
Sebastian Kaspari 346287a0ae Test project manifest: Use same sdk levels as application. 2012-11-06 21:00:36 +01:00
Sebastian Kaspari e2eb4a39f0 ServerListScenarios.testAddingAndRemovingServer(): Don't assert on number of items in list (because of "add server" item) but on existing or non-existing server name in list. 2012-11-06 20:59:45 +01:00
Sebastian Kaspari be49f407bb ScenarioHelper.connectToServer(): Don't just wait for connection but for successful server login. 2012-11-06 20:56:25 +01:00
Sebastian Kaspari 369fa7f8df Update robotium to 3.5.1. 2012-11-06 20:49:12 +01:00
Sebastian Kaspari ef09f4fc68 Mavenize test project and remove old test script. 2012-10-25 22:32:48 +02:00
Sebastian Kaspari 59ab0efd9d POM: Set android dependency to version 4.1.1.4. 2012-10-25 22:31:41 +02:00
Sebastian Kaspari 35a8d93cd0 IRCService: Extracting constants and reordering class members. 2012-10-04 19:15:18 +02:00
Daniel E. Moctezuma 89ff98b93d Added support for LED light notification on nickname highlight 2012-10-04 19:15:18 +02:00
Daniel E. Moctezuma e444354d48 Added myself to the list of contributors 2012-10-04 19:15:18 +02:00
Daniel E. Moctezuma 59ce275105 Fixed typo in LICENSE filename 2012-10-04 19:15:18 +02:00
Daniel E. Moctezuma 3f8578ef73 Replaced lowercase letters by uppercase ones on application name 2012-10-04 19:15:18 +02:00
Daniel E. Moctezuma 6dc38f5f54 Minor update to README file 2012-10-04 19:15:18 +02:00
Daniel E. Moctezuma 1cfb74a2df Minor updates to README file 2012-10-04 19:15:18 +02:00
Sebastian Kaspari 862dedb33b Update CHANGELOG. 2012-10-04 19:15:18 +02:00
Sebastian Kaspari aecb828477 Manifest: Set minSdkVersion to 7 (Android 2.2)
Due to using ActionBarSherlock we have to rise the
minSdkVersion to at least 7.

Refs #124
2012-10-04 18:59:03 +03:00
jgeboski 1a43262cb5 Allow for forward slashes in idents 2012-07-31 08:08:36 +02:00
Sebastian Kaspari 0381728018 Reorganize about dialog. 2012-07-30 22:45:59 +02:00
Sebastian Kaspari 95be86b2bf Continue with version 1.1 (SNAPSHOT). 2012-07-30 22:45:33 +02:00
Sebastian Kaspari db6ed0a122 Set version to 1.0. Updating CHANGELOG. 2012-07-29 14:25:45 +02:00
Sebastian Kaspari 56304633f4 SettingsActivity: Add up navigation. 2012-07-28 16:22:49 +02:00
Sebastian Kaspari da78ea15d0 AddServerActivity: Add up navigation. 2012-07-28 16:05:55 +02:00
Sebastian Kaspari 7c27b09298 ConversationIndicator: On updating colors invalidate title indicator. 2012-07-28 12:46:29 +02:00
Sebastian Kaspari 929d2e873e Update translations from Crowdin export.
http://crowdin.net/project/yaaic
2012-07-28 12:38:54 +02:00
remram44 0de3c817b1 Updated French translation. 2012-07-28 12:01:39 +02:00
Sebastian Kaspari 640acec6eb Mavenize Yaaic. Adding pom.xml file. 2012-07-28 11:55:32 +02:00
Sebastian Kaspari 419c2bb3cb Removing old build script. 2012-07-28 11:38:08 +02:00
Sebastian Kaspari 9c551d73bf New stateful ViewPagerIndicator.
Indicator showing the state of the current pages and off-screen pages by coloring.
2012-07-28 11:36:54 +02:00
Sebastian Kaspari 743eae9b85 Remove fullscreen option from settings.
There's no need anymore on new devices and the app should not cover the
notification bar.
2012-07-28 11:32:14 +02:00
Sebastian Kaspari 9884ef1bff DisplayUtils: Helper class for methods regarding the display of the current device. 2012-07-28 11:29:57 +02:00
Sebastian Kaspari 6f7275563c README: Update copyright year to 2012. 2012-07-28 10:33:51 +02:00
Sebastian Kaspari debc79dd59 AboutActivity: Code clean up. Some small refactorings. 2012-07-28 10:32:54 +02:00
Sebastian Kaspari a7c121ebea Update support library to r9. 2012-07-15 00:16:23 +02:00
Sebastian Kaspari b32b24c4ba Add WTF smiley to mapping (o_O). Refs #114. 2012-07-14 23:02:43 +02:00
Sebastian Kaspari d6176ca5a0 Use Android emoticons. Refs #114. 2012-07-14 22:52:24 +02:00
Sebastian Kaspari 2c73859b58 Move non XML drawables from drawables/ to drawables-mdpi/ 2012-06-22 19:17:55 +02:00
Sebastian Kaspari 8fc10e0419 ConversationActivity: Use same font size for EditText as for conversation. 2012-06-20 07:38:39 +02:00
Sebastian Kaspari 4831e71567 ServersActivity: Change order of menu items. 2012-06-20 06:59:43 +02:00
Sebastian Kaspari c511e9bcc5 ConversationActivity: Do not disable menu items. Not needed with anymore with ActionBar. 2012-06-20 06:59:03 +02:00
Daniel E. Moctezuma ca4a93d40d Added missing keys and translations to values-ja 2012-05-21 22:24:57 +02:00
Sebastian Kaspari 84c3025c26 ConversationActivity: Remove code to keep compatibility with api level 3. MinSdkVersion is 4. 2012-05-21 21:57:44 +02:00
Sebastian Kaspari 9a05d3b606 ConversationActivity: Do not determine density twice. 2012-05-21 21:53:30 +02:00
Sebastian Kaspari 8f329f475c Indicator: Do not set typeface twice. 2012-05-21 21:52:29 +02:00
Sebastian Kaspari f713466468 Update ViewPagerIndicator to 2.3.1. 2012-05-21 21:40:32 +02:00
Sebastian Kaspari 6045cd0f91 Add ActionBarSherlock to README. 2012-05-19 12:01:56 +02:00
Sebastian Kaspari 2e6292eac0 Use same version of support library in all projects. 2012-05-19 11:04:24 +02:00
Sebastian Kaspari cb5354a306 Update ActionBarSherlock to 4.1.0 release. 2012-05-19 11:00:23 +02:00
Sebastian Kaspari c292892307 Update ViewPagerIndicator dependency to latest version. 2012-04-13 11:21:56 +02:00
Sebastian Kaspari 35b896c3d6 Workaround for a race condition in EditText implementation. Fixes #67. 2012-04-12 21:42:03 +02:00
Sebastian Kaspari 5d68a5efb1 Manifest: Set installLocation to "auto". Allow installation on the external storage. 2012-04-12 22:02:59 +03:00
Jose Carlos Garcia Sogo 03b5782e82 Update Spanish translation. Fix several typos and not Spanish words. 2012-04-12 15:10:32 +02:00
Sebastian Kaspari 309c730b33 ServersActivity: Remove "Exit" from menu and replace by "Disconnect all". 2012-04-12 12:27:34 +02:00
Sebastian Kaspari 8ecb697f28 Use a Holo-like style for EditText fields. 2012-04-12 11:48:15 +02:00
remram44 493f9f758c Disabled autocompleting on some TextView's. 2012-04-04 21:31:25 +02:00
Sebastian Kaspari 5485213e52 ViewPagerIndicator dependency: Move support library to "libs" folder. 2012-04-04 21:25:29 +02:00
Sebastian Kaspari 690012504e Update ActionBarSherlock dependency to version 4.0.1. 2012-04-04 21:24:57 +02:00
Sebastian Kaspari 9f314df091 Manifest: Set touchscreen feature required to false in order to run Yaaic on GoogleTV. 2012-04-04 18:37:02 +02:00
Sebastian Kaspari 1a4f570d6e Move support library to "libs" folder of application. Will be automatically included and does not need to be in classpath. 2012-04-04 18:36:31 +02:00
remram44 e89b641536 Updated French translation. 2012-01-23 21:50:56 +01:00
Sebastian Kaspari 0ec311c074 Add own theme "Theme.Yaaic" to enforce overflow menu in action bar. 2012-01-23 21:32:20 +01:00
Sebastian Kaspari 6aff86bcb6 Server list menu: Show settings action with text if room. 2012-01-23 21:31:39 +01:00
Sebastian Kaspari d0ea5a2a2d Use shared support library in all projects. 2012-01-22 00:10:38 +01:00
Sebastian Kaspari e7c84fb694 ServerListScenarios: Fix testAddingAndRemovingServer(). 2012-01-21 23:44:31 +01:00
Sebastian Kaspari 2fbe9c4e26 ScenarioHelper: Fix createTestServer(). 2012-01-21 23:40:30 +01:00
Sebastian Kaspari 8d32855938 Update robotium to version 3.1. 2012-01-21 23:40:26 +01:00
Sebastian Kaspari 21032950b7 Update copright line (2009-2012). 2012-01-21 23:12:55 +01:00
Sebastian Kaspari fbdebc2ca5 Add ActionBarSherlock to all activities. Restructure menu items. Fixes #96. 2012-01-21 23:07:44 +01:00
Sebastian Kaspari 3e9735760a Add action bar resources. 2012-01-21 23:01:18 +01:00
Sebastian Kaspari 46a45523a8 IRCService: Use reflection to call setForeground() on old versions. 2012-01-21 12:59:02 +01:00
Sebastian Kaspari d4f2c1cc3a Set SDK target version to 15 (Android 4.0.3). 2012-01-21 12:58:27 +01:00
Sebastian Kaspari c4ba9cd35d Add ActionBarSherlock (4.0 beta) to repository. 2012-01-21 12:56:53 +01:00
Sebastian Kaspari f9615a2344 Add yaaic icon in different resolutions (ldpi, mdpi, hdpi). 2012-01-21 11:55:14 +01:00
Sebastian Kaspari b09ba251ea ConversationActivity: Make text input smaller and more "flat". 2012-01-21 11:50:58 +01:00
Sebastian Kaspari da885094da Add ViewPagerIndicator library project to project properties. 2012-01-21 11:31:33 +01:00
Sebastian Kaspari 2a51daf45c (User) action items: More padding. 2012-01-21 11:31:13 +01:00
Sebastian Kaspari 25cf7eb2ad ConversationActivity: Add ViewPagerIndicator. 2012-01-21 11:30:41 +01:00
Sebastian Kaspari 706a864f44 Add ViewPagerIndicator library project to repository.
https://github.com/JakeWharton/Android-ViewPagerIndicator

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.
2012-01-21 10:57:45 +01:00
Sebastian Kaspari 8386f4a1ef AddServerActivity: Disable auto-correction for the hostname field. Fixes #99. 2012-01-21 10:33:03 +01:00
remram44 6ff79ee50d Updated French translation. 2012-01-21 08:59:22 +01:00
Sebastian Kaspari ec90fe3db6 Make everything clickable in messages (links, email addresses, telephone numbers). 2012-01-21 08:57:28 +01:00
Sebastian Kaspari e04499070a Replace gallery view for conversations by ViewPager. Fixes #38. 2012-01-21 08:56:40 +01:00
Sebastian Kaspari 659d6c0b89 Eclipse setting: Do not "fix" indentation on save. 2012-01-21 08:21:06 +01:00
Sebastian Kaspari ca0a86d2cb Add support library to build path. Refs #38. 2012-01-12 18:45:07 +01:00
Sebastian Kaspari e6be035a8e Add target to build file. 2011-11-27 00:03:35 +01:00
Sebastian Kaspari a4bc0ada80 Update test project to Robotium 3.0. 2011-11-27 00:00:25 +01:00
Sebastian Kaspari 29e102b5d0 ServerListScenarios: Fix testAddingAndRemovingServer() test case. 2011-11-26 23:50:39 +01:00
Sebastian Kaspari d1d23ecb04 Fix incomplete build script. 2011-11-26 23:47:41 +01:00
Sebastian Kaspari e00cb44553 ScenarioHelper: Fix createTestServer(). 2011-11-26 23:40:09 +01:00
Sebastian Kaspari 2522aacb11 Update build files for test project. 2011-11-26 23:20:08 +01:00
Sebastian Kaspari a0a1d3fb3d Remove generated build files and add build script. 2011-11-26 23:09:41 +01:00
Sebastian Kaspari e7243258b9 Update build files. 2011-11-26 23:06:13 +01:00
Sebastian Kaspari bd17dcd598 ConversationReceiverTest: Fix interface implementation. 2011-11-26 22:58:15 +01:00
Steven Luo 66006cabf5 Work around a crash on ICS when destroying a ConversationActivity
On Ice Cream Sandwich, something -- possibly even in the Android
framework classes (not in our code) -- is passing in null to a
MessageListAdapter's unregisterOnDataSetObserver(), which causes a
crash.

We should really find out whether this is something we can properly fix
or not, but in the meantime, wrap the superclass's method with our own
method which checks for null before calling through to the superclass
implementation.
2011-11-26 19:41:06 +01:00
Sebastian Kaspari 5c25c86614 Authentication view: Wrap in ScrollView for smaller screen sizes. Fixes #94. 2011-11-20 14:57:37 +01:00
Jonas Häggqvist 61e1681b03 Proper case insensitive nick completion (untested) 2011-11-18 13:48:41 +01:00
Sebastian Kaspari 8c8e9e8081 Update CONTRIBUTORS. 2011-09-20 08:50:02 +02:00
Daniel E. Moctezuma c7c0b0c44e Updated japanese translation. 2011-09-20 08:47:47 +02:00
Francesco Lavra 0a8e75feff Add /back command (issue #89)
This patch adds the /back command, which turns off the away status.
This should close issue #89, https://github.com/pocmo/Yaaic/issues/89.
2011-09-05 08:41:55 +02:00
Sebastian Kaspari d155e86cd1 Russian translation (By NeKit) 2011-08-18 01:44:38 +02:00
Steven Luo e07d99ed5d Remove views from DeckAdapter when corresponding conversation has gone missing
If a conversation disappears while the activity is paused (e.g. if the
user is kicked from a channel, or if another client attached to an
irssi-proxy has chosen to leave that channel), we currently aren't
removing the view from the DeckAdapter when we resume.  This results in
leaking a Conversation object until the user explicitly asks for the
conversation to be closed or the activity finishes, and is also
confusing because the user may not receive any indication that the
channel was parted in the first place.

There's a good case for leaving the MessageListView in place, with a
note indicating that the user has been kicked or parted from the
channel, but for that to work, we need to keep the Conversation object
in the server's list of conversations -- otherwise the behavior will
differ depending on whether the user left the activity via the Back
button or the Home button, which is counterintuitive.

For now, just remove the stale view from the DeckAdapter, which fixes
the leak and the potential user confusion.
2011-08-16 11:21:43 +02:00
Steven Luo f84369bc19 Add new conversations to DeckAdapter in onResume()
Currently, when the user opens a ConversationActivity, goes off to do
something else without closing it, and then comes back to the activity,
conversations started since the ConversationActivity was paused (e.g. by
an incoming private message) will not appear in the ConversationGallery;
this is because we never check for new conversations in the onResume()
path.

Fortunately, this is an easy fix: we're already looping over all the
conversations in onResume() in order to add new messages to the
MessageListViews, so just look out for the new conversations and add
them to the ConversationGallery when we see them.
2011-08-16 11:21:40 +02:00
Steven Luo c8266fbe62 Add method to remove conversation from DeckAdapter by position
This makes the following patch to remove old conversations much more
efficient.
2011-08-16 11:21:38 +02:00
Steven Luo fafbe1ca4a Display "Not connected" in notification instead of no text when not connected 2011-08-16 11:21:33 +02:00
Sebastian Kaspari 4396e66954 Bugfix: On updating an existing server configuration the real name was overwritten by the nick name 2011-07-17 16:07:24 +02:00
Sebastian Kaspari 0b0579c475 Update CHANGELOG headline 2011-07-17 15:42:16 +02:00
Sebastian Kaspari a357c42477 IRCService: suppress rawtype warning 2011-07-17 14:40:19 +02:00
Sebastian Kaspari 39175635d9 Update CHANGELOG 2011-07-17 14:39:09 +02:00
Sebastian Kaspari e82345c1fe Typo in README 2011-07-17 14:35:56 +02:00
Sebastian Kaspari 668f7f26ae Bumped version number. Yaaic 0.9 2011-07-17 14:32:34 +02:00
Sebastian Kaspari 99b4b0929a Raise default history size to 50 messages 2011-07-17 14:32:34 +02:00
Steven Luo 02316ffdbc Remove bottom padding in MessageListView onCreate()
If we're going to do this when changing to/from switched mode, we should
do it when creating a new MessageListView too.
2011-07-03 14:08:28 +02:00
Steven Luo ec17d34e4d Miscellaneous ConversationLayout cleanups
* Simplify control flow in onMeasure() by moving height adjusting to
  a separate method
* Various whitespace changes and comment updates
2011-07-03 14:06:41 +02:00
Steven Luo e0f90768b2 Remove bogus setImeOptions() in ConversationActivity
I thought this was removed when we moved the setImeOptions() further
down in onCreate(), but it's still here somehow.  This causes the Send
key on the keyboard to disappear when fullscreen IMEs are disabled.
2011-07-03 14:06:19 +02:00
Steven Luo d80f4133f1 Ack new mentions on part or kick from a channel
If we don't do this, the user is left with a new message notification
she can't clear, and we leak the Channel object.
2011-07-03 14:03:41 +02:00
remram44 5d5ce6445a French translation updated 2011-07-03 13:18:03 +02:00
Darren Salt 2759b00084 Add an informational message for when the MOTD is ignored. 2011-07-02 19:51:32 +02:00
Sebastian Kaspari 9dba05eb2d Update CONTRIBUTORS 2011-07-02 19:51:19 +02:00
Darren Salt 23ca120f0e Only ignore the MOTD once. 2011-07-02 19:49:19 +02:00
Sebastian Kaspari a6da4970aa ConversationSwitcher: Update comment 2011-07-02 19:49:19 +02:00
Sebastian Kaspari d7070c84cf Shrinked version of Base64 class. Fixes #71. 2011-07-02 19:49:18 +02:00
Sebastian Kaspari 61252c7535 Remove unused imports 2011-07-02 19:49:18 +02:00
Rey Rey 2e2aebf2c4 Micro optimized full screen code. Made starvation mode leaner.
Conflicts:

	application/src/org/yaaic/activity/ConversationActivity.java
2011-07-02 19:49:16 +02:00
Rey Rey 5c48724425 Future proofed ime no extract support, enhanced performance of fullscreen patch.
Conflicts:

	application/src/org/yaaic/activity/ConversationActivity.java
2011-07-02 19:49:10 +02:00
Rey Rey f7ccd50227 Whitespace clean up and light refactoring
Conflicts:

	application/src/org/yaaic/activity/ConversationActivity.java
2011-07-02 19:49:06 +02:00
Rey Rey 84ade9fae4 Finalized fullscreen implementation, added heuristics to resizing, fixed ime extract bug introduced 2 commits ago.
Conflicts:

	application/src/org/yaaic/activity/ConversationActivity.java
2011-07-02 19:48:58 +02:00
Rey Rey 27d93ebaa7 Added large ime option, Extended Español support, rephrased fullscreen methodology 2011-07-02 17:55:54 +02:00
Steven Luo ccaf9f59c4 Resize the fullscreen conversation window when IME appears instead of scrolling
When an activity sets FLAG_FULLSCREEN on its window, Android assumes
that the window size will always be the same as the screen size.  This
causes the window to scroll instead of resizing when the soft keyboard
comes up, which (according to a quick Google search) isn't the behavior
most developers are expecting.

This patch implements an ugly workaround: extend the root element of the
layout (in our case, a LinearLayout) to hook into the onMeasure()
callback, which is called when the window size changes, so that we can
resize ourselves when the window size changes.
2011-07-02 17:53:41 +02:00
Steven Luo 77dec6249d Make sure a Send button is available in landscape when ImeExtract is disabled 2011-07-02 17:53:37 +02:00
Rey Rey 6da6a7b76b Added large ime option, Extended Español support, rephrased fullscreen methodology 2011-07-02 17:53:34 +02:00
Rey Rey 93e77ea6ed Fullscreen chat implementation. pans window instead of resizing, not easly fixable 2011-07-02 17:50:02 +02:00
Sebastian Kaspari a5d81a1350 about.xml: Fix indentation 2011-07-02 17:48:14 +02:00
Rey Rey 750df0de36 Extended IRC URI support and added Yaaic IRC link to about. 2011-07-02 17:47:36 +02:00
Steven Luo bce2523f98 Fix auto-reconnect
The current auto-reconnection implementation will only try reconnecting
once, immediately after the server is disconnected.  This will of course
almost always fail if the network is down or otherwise unavailable, so
as it stands, enabling auto-reconnect isn't particularly useful.

This patch implements multiple retries for auto-reconnect, with the
frequency of retries controlled by a preference.  The Android alarm
infrastructure is used to schedule reconnection attempts; if the phone
misses a scheduled attempt while it's asleep, the reconnection will be
attempted the next time the phone wakes up.
2011-06-29 20:34:55 +02:00
Steven Luo e7651315df Make reconnections actually work
At the moment, the reconnect feature is somewhat glitchy, popping up
multiple reconnect prompts even if a reconnection succeeds, and
occasionally causing crashes.  A successful reconnection results in the
conversation history being cleared, which is an annoying outcome when
connected over an unreliable network.

This patch does the following:

* Keep track of whether a reconnect dialog is active, to prevent
  multiple dialogs from opening.
* Introduce a new field to the Server object, mayReconnect, which is
  used to keep track of whether a reconnection should be attempted in
  the event of a disconnection.  It's set to "true" when we connect to a
  server, and "false" if the user asks for a disconnection.
* Prevent the clearing of active conversations and conversation history
  on disconnect, unless the user specifically asked for the disconnect.
* Keep the IRCService running even when no servers are connected, unless
  the user has disconnected from all servers herself.  This is needed
  for reliable auto-reconnects (see next patch), but has the side effect
  of keeping conversation history around even if the activity isn't open
  when a disconnect happens.
2011-06-29 20:34:52 +02:00
Steven Luo a69fafc4dd PircBot: Gracefully handle disposing of the PircBot before I/O threads are started 2011-06-29 20:34:50 +02:00
Sebastian Kaspari ae871f8a1f AddChannelActivity: Always set cursor at the end of the input field 2011-06-13 22:48:25 +02:00
remram44 8fea644007 French translation updated 2011-06-11 13:58:33 +02:00
remram44 938577128d Internationalization of Authentication GUI 2011-06-11 13:56:42 +02:00
Sebastian Kaspari 6e48a29b34 Display message at the beginning and end of the server login 2011-06-10 22:29:17 +02:00
Sebastian Kaspari 2f19eb8032 (Authentication) Implementation of authentication via SASL on connect 2011-06-10 22:03:19 +02:00
Sebastian Kaspari 4739d292c5 Add Base64 helper class (Written by Robert Harder) - Needed for SASL implementation 2011-06-10 21:42:06 +02:00
Sebastian Kaspari d9d1c4aba8 (Authentication) Implementation of authentication via NickServ on connect 2011-06-10 21:36:14 +02:00
Sebastian Kaspari 2fde7559e3 (Authentication) GUI for NickServ and SASL 2011-06-10 21:35:23 +02:00
Sebastian Kaspari 571090aa13 Update CONTRIBUTORS 2011-06-09 20:36:06 +02:00
Jonas Häggqvist d4e22f3846 Ignore status characters in front of nicks for the purpose of nick completion 2011-06-09 20:33:35 +02:00
Sebastian Kaspari 7c7ce7cc41 channeladd.xml view: Replace tabs with white spaces 2011-06-09 00:02:34 +02:00
Sebastian Kaspari 862d6664d4 Update CONTRIBUTORS 2011-06-08 23:21:43 +02:00
Sebastian Kaspari 5fa92b9cf4 ConversationClickListener: Remove unused imports 2011-06-08 23:17:59 +02:00
Sebastian Kaspari 14ed6f7f2b IRCService: Code cleanup and suppress warnings 2011-06-08 23:17:31 +02:00
Sebastian Kaspari 2350e9743a DeckAdapter: Remove unused imports 2011-06-08 23:16:49 +02:00
Sebastian Kaspari 1a820d9609 ConversationActivity: Code cleanup, remove unused imports and unused code 2011-06-08 23:16:27 +02:00
Steven Luo aaf3f3e332 Prevent race between IRCConnection dispose() and onDisconnect() when quitting
When the user asks for a disconnect from the ConversationActivity, there
is a race between the IRCConnection, which is waiting for the server to
acknowledge the QUIT before calling onDisconnect(), and the IRCService,
which will invoke dispose() on the IRCConnection when
checkServiceStatus() is called during the activity shutdown.  If the
dispose() wins, the thread running the onDisconnect() is terminated,
leading to the cleanup being unfinished.  This causes the disconnect
notification to be unreliable, and can result in the list of servers in
the ongoing notification to be out of sync with reality.

To fix this, introduce a new field isQuitting to the IRCConnection,
which is set to true when quitServer() is called and cleared once
onDisconnect() has finished.  If dispose() is called while isQuitting is
set, it sets disposeRequested instead of doing the dispose itself, and
onDisconnect() will call through to super.dispose() once it's finished.

Note that this requires a change to PircBot to allow the overriding of
quitServer(String message), which is declared final upstream.
2011-06-08 23:11:29 +02:00
Steven Luo a9621b66b4 Bugfix nick completion / autocorrect
Use clearComposingText() when inserting nick completion to ensure
that autocorrect doesn't try to replace the completed nick on the next
keypress; thanks Thomas Martitz for pointing out the bug
2011-06-08 23:11:28 +02:00
Steven Luo dc95472aaf Fix broadcast on topic change 2011-06-08 23:11:28 +02:00
Steven Luo 06e0849c17 Bugfix notification system
* If there's a new message notification, keep showing the "New messages
   in" content text, even after a disconnect notification.
 * Handle the case of a channel/query name duplicated between two or more
   connections more gracefully in new message notifications
 * Fix a race in updating notifications
2011-06-08 23:11:28 +02:00
Steven Luo 35609e5529 IME behavior changes for the ConversationActivity
(1) Let full-screen IMEs wrap the text into multiple lines instead of
making the text scroll off the screen.

(2) Provide a preference to let the user choose whether or not to enable
autocorrection of typed text.

(3) Provide a preference to let the user choose whether or not to enable
autocapitalization of sentences.  Note that even when this is enabled,
autocapitalization will only happen if the option is also enabled in the
IME.

(4) In landscape mode only, don't replace the Enter key with a Send
button, to make it harder to accidentally send a message.  (We can't do
this in portrait, because we would be left without any send button at
all -- perhaps the input line should be changed to be similar to the
text message application, which has a send button next to the input
line?)
2011-06-08 23:11:28 +02:00
Steven Luo aa355c4283 Rewrite onKey handling for the ConversationActivity input line
The current method of supplying an onKey handler for the input line
(having the activity implement OnKeyListener) is somewhat unusual -- the
documentation recommends creating an anonymous inner class to pass to
setOnKeyListener().  Do this, while refactoring the code to make it
somewhat more readable and removing some instances of code duplication.
2011-06-08 23:11:28 +02:00
Steven Luo 91d211c51d Make the conversation history size a configurable preference 2011-06-08 23:11:28 +02:00
Steven Luo 61960c9add Overhaul notifications system
Features:
* Now displays the number of mentions that the user has not seen in the
  notification.
* When no mentions are outstanding, display which servers the user is
  connected to, not the last message.
* When more than one mention is outstanding, display the names of the
  conversations with new mentions, not just the last message received.
* Notifications of mentions are suppressed if you're in the conversation
  at the time of the mention.
* Notifications of mentions automatically clear when you bring up the
  conversation.
* Vibrate notifications now generate the user's chosen default vibrate
  pattern, not a hard-coded one.
* Add ticker text to the notification that's displayed when the IRCService
  goes into the foreground, instead of displaying a blank ticker.

To allow for all of this, the implementation moves most of the details
of generating the notification text into the IRCService, which now
exposes addNewMention() and notifyConnected()/notifyDisconnected()
methods instead of the lower-level updateNotification().
2011-06-08 23:11:28 +02:00
Steven Luo 09fedc6975 Include channel topic in the displayed conversation title 2011-06-08 23:11:28 +02:00
Steven Luo 9a8bf44d63 Do something sane for private messages where the sender is our nick
As of now, private messages where the sender is our nick end up in
a query window targeted at us.  Show these messages in the query window
of the target instead, which is probably what we want.

This is useful for use with irssi proxy, which will send messages sent
by another client attached to the proxy to us in this way.

(Note that this patch makes a change to PircBot to pass the target of a
private message to the onPrivateMessage handler.)
2011-06-08 23:11:28 +02:00
Steven Luo 159cb8195d Remember switched conversations across screen orientation changes
As of now, the activity does not remember whether a conversation is
switched across configuration changes (such as screen rotations).  Fix
this by adding onSaveInstanceState() and onRestoreInstanceState()
callbacks in the activity to pass this information to the new instance.

To make the implementation of this simpler, all code to configure the
MessageListView, which was duplicated in several places in the codebase,
has been moved to the MessageListView's constructor.

While we're at it, make the padding setting independent of screen
density instead of specifying in fixed pixels (equivalent to specifying
the value in dp instead of px), and increase the padding for switched
views.  This ensures that message text isn't obscured by the gradient at
the edges of the ConversationGallery, which started happening when we
began caching MessageListViews in the DeckAdapter.
2011-06-08 23:11:28 +02:00
Steven Luo c9ed28767d Actually deliver actions to existing private message windows 2011-06-08 23:11:28 +02:00
Steven Luo ae1b574997 Dispose of IRCConnections properly to avoid leaking IRCService objects
Each IRCConnection starts an input thread and an output thread when
created; if not stopped, these threads continue to hold the IRCService,
resulting in a leak when the service is stopped.  Fix this by using
PircBot's dispose() to stop the threads when disposing of the
IRCConnection.
2011-06-08 23:11:28 +02:00
Steven Luo ffe73b7c9f Hold MessageListAdapters and MessageListViews in DeckAdapter to avoid leaks
There are at least two significant memory leaks in Yaaic, which cause
the client to force close after a few hours with an
OutOfMemoryException:

(1) The IRCService holds Conversation objects, which contain a
MessageListAdapter, which have references to the ConversationActivity
context.  This causes Activity contexts to outlast the Activity, causing
a significant memory leak over time.

Fix this by holding the MessageListAdapter in the ConversationActivity's
DeckAdapter instead of in the Conversation objects.  The DeckAdapter's
lifecycle matches that of the Activity, so this prevents the leak.

(2) Every call to DeckAdapter.getView()/renderConversation() creates a
new MessageListView and adds it to the deck.  But adding the view to
the deck causes the deck to take a reference to the view, leaking the
MessageListView until the Activity is finished.  (This has the effect of
exacerbating the first leak, since the Activity context holds a
reference to the deck.)

Fix this leak by caching MessageListViews in the DeckAdapter, and
returning an existing MessageListView for a Conversation in getView() if
one already exists.
2011-06-08 23:11:28 +02:00
Steven Luo c4504be725 Notify the user on receipt of all private messages, not just ones with nick mentions
You'd rarely use someone's nick in a privmsg with them, and this matches
the behavior of other clients.
2011-06-08 23:11:28 +02:00
Steven Luo 464430ee74 Add FLAG_ACTIVITY_NEW_TASK to notification intents
According to
http://developer.android.com/reference/android/app/Notification.html#contentIntent
we should do this.  Suppresses a log message when tapping on our status
bar notification.
2011-06-08 23:11:27 +02:00
Steven Luo caf3272f71 Ensure privmsg with mention of user's nick opens new query when appropriate
If a private message that should open a new query window contains a
mention of the user's nick, the expected new window fails to open
because the isMentioned() path tries to use
server.getConversation().setStatus(), and server.getConversation() is
null in this case.  Fix this by moving the attempt to highlight the
window to a point where a conversation is guaranteed to exist.
2011-06-08 23:11:27 +02:00
Steven Luo f1b57c9e25 Don't scroll to a conversation in onCreate() unless it was previously selected
This has two advantages:
(1) The activity remembers which conversation was last selected if it's
    destroyed (e.g. via the Back button) and then recreated with the connection
    still running.
(2) It prevents onCreate() from clearing all the mentioned notifications for
    the conversations in that activity.
2011-06-08 23:11:27 +02:00
remram44 3102340762 Corrected CONTRIBUTORS list 2011-06-08 23:11:17 +02:00
Sebastian Kaspari 1201931de1 Updated CONTRIBUTORS list 2011-05-06 17:21:35 +02:00
Sebastian Kaspari b4493b81a4 Add danish translation (By rasher) 2011-05-06 17:18:20 +02:00
Matt Mastracci ac4fa4a104 Add _ to ident chars, update comment 2011-04-24 20:53:40 -06:00
remram44 322c4e0ac8 French translation updated 2011-04-17 05:36:37 +08:00
Sebastian Kaspari daf07014f8 Update CHANGELOG 2011-04-15 22:05:27 +02:00
Sebastian Kaspari c20cd695e6 Updated version number: Yaaic 0.8 2011-04-15 22:00:55 +02:00
Sebastian Kaspari 1e5f016012 DeckAdapter: getView(): If no conversation is available (anymore) for the requested position, return an empty TextView. Fixes #56. 2011-04-15 20:39:33 +02:00
Sebastian Kaspari 50a6047edd On own nick change: Display message in server info window (Your are now known as ...). Fixes #51. 2011-04-15 20:30:46 +02:00
Sebastian Kaspari c6dbe8cc18 Remove color codes if the mirc colors option is off. Fixes #57 2011-04-14 22:53:38 +02:00
Sebastian Kaspari 86e0812741 Ooops, fix @author javadoc tag in classes: MircColors, Smilies 2011-04-13 00:14:40 +02:00
Sebastian Kaspari 4e266e1bb7 ConversationActivity: onCreate(): Check if server is returned by getServerById() - Fixes #55 2011-04-12 23:44:39 +02:00
Sebastian Kaspari 9387a02068 ConversationActivity: onStatusUpdate(): Check if service is already connected and initialized - Fixes #54 2011-04-12 23:37:11 +02:00
Sebastian Kaspari ded6485f6b Database: isTitleUsed(): Escape server title (SQLiteException) - Fixes #53 2011-04-12 23:30:00 +02:00
Sebastian Kaspari b3fd4157dc JoinActivity: Set cursor position 2011-04-12 23:05:09 +02:00
Sebastian Kaspari dd07bd358a Bugfix: Only automatically change nickname on server code 433 if not already registered with server 2011-04-12 22:23:51 +02:00
Sebastian Kaspari aa5a081c02 Bugfix: Remember new nickname on auto nickname change (433: Nickname is already in use) 2011-04-12 22:07:09 +02:00
José Antonio Pérez Sánchez 2b3ce5132a fixed missing angle in closing tag 2011-03-30 16:07:37 +02:00
Sebastian Kaspari dbf7983eec Updated turkish translation 2011-03-27 22:23:39 +02:00
Sebastian Kaspari b798d4dacb Setting mIRC colors off by default 2011-03-27 20:02:42 +02:00
Sebastian Kaspari 591dc8f763 MircColors/Smilies: Code formatting and documentation 2011-03-27 20:02:06 +02:00
Sebastian Kaspari 673598ad31 Added licence header to new files 2011-03-27 19:53:05 +02:00
liato ac1a07894f Add support for graphical smilies in chat. 2011-03-27 19:51:47 +02:00
liato 92a1e93bc1 Use TextUtils.concat to concatenate 2011-03-27 19:43:51 +02:00
liato 7490cdb38c Change settings text for mirc colors. 2011-03-27 19:43:34 +02:00
liato eea82e506f Rename Colors class and methods. 2011-03-27 19:42:47 +02:00
liato 2189d2c05f Remove tagsoup dependency. Improve mIRC color code parsing speed. 2011-03-27 19:42:05 +02:00
liato 7c4abe0c9c Render colors correctly in topics and other foreground colored places. 2011-03-27 19:41:13 +02:00
liato 59c70a750d Fix mirc color bug by changing the tagsoup schema and making the font tag restartable. 2011-03-27 19:40:47 +02:00
liato 624f8c5014 Add support for mIRC colors. 2011-03-27 19:40:26 +02:00
liato e612d3b09c Render html in messages to spannables. 2011-03-27 19:37:35 +02:00
Sebastian Kaspari bd19398d65 Added turkish translation (Thanks to Hasan Kiran) 2011-03-27 18:21:22 +02:00
Sebastian Kaspari 9b776aef15 Update CHANGELOG 2011-03-27 17:41:28 +02:00
Sebastian Kaspari ba9f6c6544 Increment version number (0.7) 2011-03-27 17:28:22 +02:00
liato 1f9c8efcca Fix nullpointerexception. 2011-03-27 17:16:38 +02:00
liato 1ebea8f7d6 Use integer division to calculate gallert item width. 2011-03-27 17:13:09 +02:00
liato b49ead73ad Fix width issues in gallery. 2011-03-27 17:10:54 +02:00
Sebastian Kaspari 7563437343 Server: Fix typo in addConversation() 2011-03-15 23:59:49 +01:00
Sebastian Kaspari 78a47ca17b dp/sp: More adjustments 2011-03-15 22:11:55 +01:00
Sebastian Kaspari 214a786175 useritem.xml: Use dp for padding and sp for fonts 2011-03-15 21:31:53 +01:00
Sebastian Kaspari f44aea0d5e channelitem.xml: Use dp for padding and sp for fonts 2011-03-15 21:31:53 +01:00
Sebastian Kaspari 23ed9c3343 aliasitem.xml: Use dp for padding and sp for fonts 2011-03-15 21:31:53 +01:00
Sebastian Kaspari 4713c22655 useritem.xml: Replace px by sp/dp 2011-03-15 21:31:53 +01:00
Sebastian Kaspari 7e559f288e user.xml: Replace px by sp/dp 2011-03-15 21:31:53 +01:00
Sebastian Kaspari f71e89e1ee serveritem.xml: Replace px by sp/dp 2011-03-15 21:31:53 +01:00
Sebastian Kaspari 3e188a0445 serveradd.xml: Replace px by sp/dp 2011-03-15 21:31:52 +01:00
Sebastian Kaspari 7d4194a1ea rounded.xml: Identation 2011-03-15 21:31:52 +01:00
Sebastian Kaspari f46887d9ee message.xml: Replace px by sp/dp 2011-03-15 21:31:52 +01:00
Sebastian Kaspari f5b29ef01a join.xml: Replace px by sp/dp 2011-03-15 21:31:52 +01:00
Sebastian Kaspari 22fb895ad3 conversations.xml: Replace px by sp/dp 2011-03-15 21:31:52 +01:00
Sebastian Kaspari c06b6b7296 commanditem.xml: Replace px by sp/dp 2011-03-15 21:31:52 +01:00
Sebastian Kaspari 533a8ec97b commandadd.xml: Replace px by sp/dp 2011-03-15 21:31:52 +01:00
Sebastian Kaspari acb7f0d100 channelitem.xml: Replace px by sp/dp 2011-03-15 21:31:51 +01:00
Sebastian Kaspari 59755b376c channeldialog.xml: Replace px by sp/dp 2011-03-15 21:31:51 +01:00
Sebastian Kaspari 3156e3b704 channeladd.xml: Replace px by sp/dp 2011-03-15 21:31:51 +01:00
Sebastian Kaspari 836e9ee6cd aliasitem.xml: Replace px by sp/dp 2011-03-15 21:31:51 +01:00
Sebastian Kaspari 7ba3303892 aliasadd.xml: Replace px by sp/dp 2011-03-15 21:31:51 +01:00
Sebastian Kaspari e486d34189 Modify dp settings in about.xml 2011-03-15 21:31:51 +01:00
Sebastian Kaspari 1b5f8ef0e9 addserveritem.xml: Replace px by sp/dp 2011-03-15 21:31:51 +01:00
Sebastian Kaspari ff6abb7828 actionitem.xml: Replace px by sp/dp 2011-03-15 21:31:50 +01:00
Sebastian Kaspari 0dc194cefc about.xml: Replace px by sp/dp 2011-03-15 21:31:50 +01:00
Sebastian Kaspari 4262cbcd15 New Setting: Show notices in server window. Closes #47. 2011-03-15 20:53:47 +01:00
Sebastian Kaspari b855b7ea92 Hide join/part setting now hides quit messages too 2011-03-15 20:42:35 +01:00
Sebastian Kaspari 49f067cd67 IRCConnection: Formatting 2011-03-15 20:12:12 +01:00
Sebastian Kaspari 488924546f Fix unit test MessageTest after refactoring 2011-03-14 22:32:28 +01:00
Sebastian Kaspari 95f3c4b255 Some more simple refactorings 2011-03-14 22:15:13 +01:00
Sebastian Kaspari 1c8076ec53 Refactoring of Message class 2011-03-11 22:07:39 +01:00
liato a3ebf8d5d0 Handle auto joins after the user has registered with the server. 2011-03-09 08:54:28 +01:00
Sebastian Kaspari 84d45c5f5c Refactor ConversationSwitcher: onDraw() - May throw ConcurrentModificationException 2011-03-06 14:21:58 +01:00
Sebastian Kaspari 635b90b5da Fix NullPointerException when using upercase characters in command names 2011-03-06 14:03:34 +01:00
Sebastian Kaspari d2a638d527 Updated CONTRIBUTORS 2011-03-06 13:48:51 +01:00
Sebastian Kaspari 5ea5b800b8 Fix testrunner script 2011-03-06 11:49:33 +01:00
Sebastian Kaspari 3f18a678ce Migrate test project to Android 1.6 too 2011-03-06 11:31:50 +01:00
Sebastian Kaspari 1e0a15c110 Use view with new name in XML 2011-03-06 11:25:49 +01:00
Sebastian Kaspari 7845ad73f0 Refactor ChannelList to ConversationGallery - Moved to view package, added javadoc and licence header 2011-03-06 11:21:28 +01:00
Thomas Martitz f4637ac582 Use a different color for join/part/quit for the circles in the ConversationSwitcher view.
This makes it easier to ignore unintersting messages wihout turning off the setting to show joins/parts/quits.
Once circle is colored for a new message, the join/part/quit cannot override it anymore.
2011-03-06 11:11:17 +01:00
Thomas Martitz 70b5ee876d Tweak some nick colors to be better readable on Yaaic's dark background. 2011-03-06 11:00:54 +01:00
Thomas Martitz db91a85676 Reduce sensitivity of the channel gallery view.
Higher scroll speeds are reduced stronger.
2011-03-06 11:00:02 +01:00
Thomas Martitz 7120bb48ea Work around duplicated activities.
With activity:launchMode = standard, we get duplicated activities
depending on the task the app was started in. In order to avoid
stacking up of this duplicated activities we keep a count of this
root activity and let it finish if it already exists

Launching the app via the notification icon creates a new task,
and there doesn't seem to be a way around this so this is needed
2011-03-06 10:59:22 +01:00
liato efecd7c6f7 Make compatible with sBNC and other IRC bouncers. Closes #19. 2011-03-06 10:59:13 +01:00
liato 33f181de3c Reopen last opened channel/activity when app is resumed. Closes #35. 2011-03-06 10:59:02 +01:00
Sebastian Kaspari b4f3fc4a15 Add server activity: Add content description for accessibility 2011-02-19 21:58:37 +01:00
Sebastian Kaspari e169627905 Target and minimum SDK Version set to 4 (Android 1.6) 2011-02-19 21:09:44 +01:00
Sebastian Kaspari 97c382c893 ServerListAdapter: Updated color codes 2011-02-11 12:54:48 +01:00
Sebastian Kaspari 8c5258710f PircBot Patch: Parse nicknames without host part (bugfix for irssi proxy) 2011-02-09 00:42:05 +01:00
Sebastian Kaspari f6a518462c PircBot Patch: Set nickname outside of connect loop. Otherwise server replies setting the nickname during connect may be overwritten (bugfix for irssi proxy) 2011-02-09 00:40:31 +01:00
Sebastian Kaspari b3e26c626b ServerListAdapter: Change server label color in list depending on connect state 2011-02-08 23:58:04 +01:00
Sebastian Kaspari b1a8c5d539 Removed empty line from CONTRIBUTORS file 2011-02-08 23:57:32 +01:00
Sebastian Kaspari 669113610a New user action view and new actions: reply, query 2011-02-05 16:04:36 +01:00
Sebastian Kaspari 984fbd7efa Add action icons 2011-02-05 15:57:04 +01:00
Sebastian Kaspari d4f05e5c13 New icons for disconnected/connecting/connected 2011-02-05 15:44:09 +01:00
Sebastian Kaspari c35e1fc1ab PircBot Patch: Recognize "%" as a nickname prefix 2011-02-05 15:23:41 +01:00
Sebastian Kaspari cf5ea6049c Added #yaaic to README 2011-02-05 14:07:16 +01:00
Sebastian Kaspari ca6e342c9d "Add" layouts: Use minimum width for small buttons 2011-02-05 14:04:43 +01:00
Sebastian Kaspari 450ba9c7a2 Added list of contributors 2011-02-05 13:30:11 +01:00
Sebastian Kaspari 68fc686ccf Added italian translation (Thanks to Gianmarco Laggia!) 2011-02-05 13:08:14 +01:00
Sebastian Kaspari d8b1a0218f Added 2011 to licence header 2011-02-05 13:00:12 +01:00
Sebastian Kaspari dddfd2e0aa Updated README 2011-02-05 12:49:50 +01:00
Sebastian Kaspari 0fb2338f9c Code cleanup (Formatting) 2011-01-25 21:02:27 +01:00
Sebastian Kaspari 4edaa4436d Adjusted code formatter (eclipse) 2011-01-15 23:49:25 +01:00
Sebastian Kaspari feaf1d4aea Fix sound notification 2011-01-15 23:38:56 +01:00
Sebastian Kaspari 7c63155cfb Fix voice recognition: Only add top match to the text input (and code cleanup) 2011-01-15 23:17:24 +01:00
Sebastian Kaspari e68ef9c8c2 Ident: Add "-" to the list of allowed characters 2011-01-15 22:52:16 +01:00
Sebastian Kaspari a315fbb6fa Fix typo: "joines" -> "joins" 2011-01-12 23:14:10 +01:00
Sebastian Kaspari e0b4b3d25d Allow chars '[' and ']' in ident 2010-12-17 23:37:00 +01:00
Sebastian Kaspari aaa313e805 Use robotium 2.0.2 (classpath) 2010-12-17 23:30:47 +01:00
Sebastian Kaspari 7764351a37 Run all scenario tests and cleanup after each test 2010-12-17 23:30:32 +01:00
Sebastian Kaspari 414bc658ba ScenarioTests: Only enable ChannelScenarios 2010-12-17 23:13:03 +01:00
Sebastian Kaspari 78ca7deebc Update robotium: 1.8.0. -> 2.0.2 2010-12-17 23:12:31 +01:00
Sebastian Kaspari e014165a17 New setting: Play (notification) sound on highlight 2010-12-17 22:29:33 +01:00
Sebastian Kaspari 4b3e47c799 Set vibration pattern (default does not always work) 2010-12-17 22:19:36 +01:00
Sebastian Kaspari 832a462bfd Added changelog to project 2010-12-17 21:54:09 +01:00
Sebastian Kaspari 4d04ca810d Bumping version to 0.6.1 2010-12-17 20:44:48 +01:00
Sebastian Kaspari c60644521a Fix french and spanish translation that may cause force closes on connects 2010-12-17 20:22:28 +01:00
Sebastian Kaspari 890fc1c50f Settings: typo 2010-11-21 12:58:17 +01:00
Sebastian Kaspari 7d080a8134 Eclipse settings for code formatting 2010-11-21 12:57:53 +01:00
Sebastian Kaspari 82e62db96c New setting: Hide join and part messages 2010-11-18 19:25:26 +01:00
Sebastian Kaspari 3b50e5a095 ServerListScenarios: some time adjustments 2010-11-18 18:56:27 +01:00
Sebastian Kaspari 6c3597ff80 IRCConnection: Just a bracket fix 2010-11-18 18:55:19 +01:00
Sebastian Kaspari 02b7ec1741 Replace all tabs with four spaces! 2010-11-18 18:52:19 +01:00
Sebastian Kaspari f3f195f631 IRCService: Added javadoc 2010-11-18 18:47:12 +01:00
Sebastian Kaspari ce0650d711 IRCService: Fixed a NullPointerException 2010-11-18 18:43:37 +01:00
Sebastian Kaspari 46cb3f9f17 AndroidManifest.xml: Indentation 2010-11-18 18:43:04 +01:00
Sebastian Kaspari 6d2a6bff14 IRCService: imports 2010-11-18 18:33:22 +01:00
liato 3708a9c60c Small modification to the nick matching regular expression. 2010-11-17 02:53:08 +01:00
liato f5b5b99adb Improve detection for nickname in messages. This will prevent notifications from poping up when a word contains the nickname. 2010-11-17 02:36:52 +01:00
liato 81f2c94b87 Added setting to vibrate on highlight. 2010-11-17 01:32:09 +01:00
Sebastian Kaspari 1d2f6e5237 Bumped version number (0.6) 2010-11-16 12:14:28 +01:00
Sebastian Kaspari d23e984e21 Scenarios regarding channels of a server 2010-11-07 13:32:26 +01:00
Sebastian Kaspari 37f12b6ab7 Test scenarios including connecting to a server 2010-11-07 13:32:00 +01:00
Sebastian Kaspari 514aaf5cf1 Scenario helper for performing common actions 2010-11-07 13:30:56 +01:00
Sebastian Kaspari 72c75b4dae First version of a test scripts that starts the emulator and runs all tests 2010-11-07 10:21:11 +01:00
Sebastian Kaspari 0b82433320 First scenario test (via robotium) for ServersActivity 2010-11-07 09:27:55 +01:00
Sebastian Kaspari 6a237792e6 Added robotium to the build path 2010-11-07 08:45:03 +01:00
Sebastian Kaspari f4b30f0217 Fixed build script 2010-11-07 08:43:58 +01:00
Sebastian Kaspari eba7788038 Added robotium lib for scenario testing 2010-11-07 08:37:38 +01:00
Sebastian Kaspari 6f82e84484 Fixed check_languages.rb script 2010-11-07 08:37:16 +01:00
Sebastian Kaspari 1250c10d9c Merged application and test project into one repository 2010-11-07 08:35:45 +01:00
Sebastian Kaspari 59ef955987 Disabled voice recognition button by default 2010-11-04 14:56:44 +01:00
Sebastian Kaspari c92a3dce8b Removed default task from build.xml (Eclipse is beside itself) 2010-11-04 14:56:27 +01:00
Sebastian Kaspari ebea92ccf8 Build script: Fixed check for build.conf 2010-11-03 16:34:17 +01:00
Sebastian Kaspari b2e37a8644 Moved config for build script to build.conf 2010-11-03 16:31:17 +01:00
Sebastian Kaspari 952a1c6782 Build script for buildung releases (apk) 2010-11-03 14:31:26 +01:00
Sebastian Kaspari 9e91c6b2b9 Removed key.store and key.alias from build.properties. Will be moved to build script 2010-10-29 20:22:21 +02:00
Sebastian Kaspari f8a5fde6fb Replaced server_add with server_save ("Add server" -> "Save") 2010-10-29 19:03:17 +02:00
Sebastian Kaspari 3f469d4074 config files for building yaaic via ant 2010-10-29 00:26:01 +02:00
Sebastian Kaspari 99cf534f20 UserActivity: Do not update list in Thread. Use a background task later 2010-10-27 23:14:25 +02:00
Sebastian Kaspari 4fc593050f Nick completion via search button - completes current selection or at the cursor position (Patch by Thomas Martitz) 2010-10-27 21:30:17 +02:00
Sebastian Kaspari 510d3967c6 UserActivity: Sort list of users (Patch by mloskot - http://github.com/mloskot) 2010-10-27 20:36:27 +02:00
diegok baa9dd438c Spanish translation added (Yaaic habla español) 2010-10-14 13:27:39 +02:00
Remi Rampin 6127dcedd6 More strings internationalized 2010-10-05 18:31:07 +02:00
Remi Rampin 2c4a2a7969 Various fixes for strings that were still displayed in English 2010-10-05 17:46:10 +02:00
Remi Rampin a3fbd38b24 French translation added 2010-10-05 17:45:38 +02:00
Sebastian Kaspari 5e0888775b Updated german language file (54.88%) 2010-09-29 18:07:45 +02:00
Sebastian Kaspari 2b2fdeb6ae Updated chinese language file (100%) 2010-09-29 18:00:03 +02:00
Sebastian Kaspari 01cedbab92 check_languages.rb: Check all languages and show statistics 2010-09-23 14:00:54 +02:00
Sebastian Kaspari d86e90d6e9 I18N: German version of strings.xml (work in progress) 2010-09-23 13:09:41 +02:00
Sebastian Kaspari 6ced20032d I18N/strings.xml: Merged current japanese version and english version 2010-09-23 13:05:10 +02:00
Sebastian Kaspari d9da2d022e Added japanese language file (Translated 17.07%) 2010-09-23 12:56:43 +02:00
Sebastian Kaspari 059f21d983 chinese language file update 2010-09-23 12:19:12 +02:00
Sebastian Kaspari f10aa55d5d check_language.rb: Scan for existing languages and check all 2010-09-23 12:16:04 +02:00
Sebastian Kaspari 5df472fe11 check_language.rb: Added basepath (script is now callable from everywhere) 2010-09-23 12:03:38 +02:00
Sebastian Kaspari 14a76d2c95 check_language.rb script: check if there are untranslated strings in a specific language file 2010-09-23 11:57:29 +02:00
Sebastian Kaspari 075164bd51 chinese language file (by 江珑) 2010-09-22 18:16:54 +02:00
Sebastian Kaspari be07e2e0ad ServerListAdapter: Added missing java doc 2010-09-18 16:31:11 +02:00
Sebastian Kaspari d447990a35 ServersActivity: Hide background if there is more than two servers 2010-09-18 16:27:11 +02:00
Sebastian Kaspari c818458a97 ServersActivity: Make list accessible via property and replace calls to getListView() 2010-09-18 16:26:04 +02:00
Sebastian Kaspari 7411db41f9 Fixed layout of command list (NullPointerException) 2010-09-18 16:13:36 +02:00
Sebastian Kaspari 43f8f7af62 Colored nicks off by default (Settings should not change with upgrade) 2010-09-18 16:07:54 +02:00
Sebastian Kaspari e136a56d7d ConversationActivity: Fixed a NullPointerException 2010-09-18 12:48:02 +02:00
Sebastian Kaspari a535d74a85 ServerListActivity: Show "Add server" item if no server in database yet 2010-09-18 10:53:39 +02:00
Sebastian Kaspari 8775d93020 IRCConnection: imports 2010-09-18 09:40:16 +02:00
Michael Imamura 8c5af16b29 Only enable the "Add" button when the alias input field is non-empty. 2010-09-10 15:00:44 +08:00
Michael Imamura 288a1a9093 Aliases are now configurable. 2010-09-10 15:00:43 +08:00
Michael Imamura b9c1363a2d Allow specifying a list of aliases to use before resorting to appending numbers. 2010-09-10 15:00:41 +08:00
Sebastian Kaspari 26330bdf99 identation 2010-09-10 08:26:08 +02:00
chantra 30dc021129 Adding nickname colors 2010-09-09 20:41:55 +02:00
Sebastian Kaspari 6691b9ad1b Removed server command whitelist. Send every unknown command to the server (otherwise some bouncer commands can't be used) 2010-09-06 17:14:43 +02:00
Sebastian Kaspari 1f0df9caaf Added font sizes: 17, 18, 19, 20 2010-09-06 16:35:17 +02:00
Sebastian Kaspari 60bb5759ef ConversationActivity: imports 2010-09-06 16:31:59 +02:00
Sebastian Kaspari 4622579189 strings.xml: wording 2010-09-05 22:36:25 +02:00
Sebastian Kaspari a4595bf756 strings.xml: indentation 2010-09-05 22:27:56 +02:00
Sebastian Kaspari 8901056b17 Voice recognition can now be disabled via settings 2010-09-05 22:04:55 +02:00
Sebastian Kaspari e29a6ec7af ConversationActivity: Added missing string to strings.xml 2010-09-05 21:19:28 +02:00
Sebastian Kaspari caaa5395fd Added shortcut: /w -> /whois 2010-09-05 21:10:27 +02:00
Sebastian Kaspari 307605e594 Removed unused string 2010-09-05 21:07:28 +02:00
Sebastian Kaspari eeb26335ac New icons: connected, connecting, disconnected 2010-09-05 20:52:17 +02:00
Sebastian Kaspari aacc0a85c2 Set font size for conversations in settings (8px - 16px) 2010-09-05 20:22:19 +02:00
Sebastian Kaspari 6c9094b7e0 Added strings of SettingsActivity to strings.xml 2010-09-05 19:21:44 +02:00
Sebastian Kaspari 9f2e16e2ce I18N: Added all strings from the layouts to strings.xml 2010-09-05 18:24:22 +02:00
Sebastian Kaspari 802de03689 I18N: Added all conversation messages to strings.xml 2010-09-05 18:02:53 +02:00
Sebastian Kaspari 1f206371bd I18N: Added new string ressources for handlers to strings.xml 2010-09-05 16:25:41 +02:00
Sebastian Kaspari 5ea7d49c34 I18N: All handlers now read their string from resources 2010-09-05 16:25:18 +02:00
Sebastian Kaspari 84fedf8be2 I18N: EchoHandler 2010-09-05 16:24:41 +02:00
Sebastian Kaspari 25cfb5a980 I18N: DevoiceHandler# 2010-09-05 16:24:20 +02:00
Sebastian Kaspari ba16f15079 I18N: DeopHandler 2010-09-05 16:24:08 +02:00
Sebastian Kaspari 9e33ec9b01 I18N: DCCHandler 2010-09-05 16:13:06 +02:00
Sebastian Kaspari 2a55b81049 I18N: CloseHandler 2010-09-05 16:12:48 +02:00
Sebastian Kaspari 72301331f2 I18N: Added all command descriptions to the strings ressource 2010-09-05 16:05:51 +02:00
Sebastian Kaspari 943b4635dc Current version of strings.xml 2010-09-05 15:57:29 +02:00
Sebastian Kaspari 5e78c020a1 I18N: Added stubs for translation 2010-09-05 15:56:58 +02:00
Sebastian Kaspari 90459a156f I18N: ServersActivity 2010-09-05 15:44:20 +02:00
Sebastian Kaspari 9d2011330f I18N: ConversationActivity 2010-09-05 15:42:47 +02:00
Sebastian Kaspari e6ba6f4bad I18N: AddServerActivity 2010-09-05 15:31:53 +02:00
Sebastian Kaspari c5b52e95c1 I18N: AddCommandsActivity 2010-09-05 15:31:42 +02:00
Sebastian Kaspari 8fc5ca054d I18N: AddChannelActivity 2010-09-05 15:31:29 +02:00
Sebastian Kaspari 17aba7ca71 Added voice recognition to yaaic 2010-08-29 16:42:50 +02:00
330 changed files with 15743 additions and 9958 deletions

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin"/>
</classpath>

19
.gitignore vendored
View File

@ -1,8 +1,23 @@
#
# Git Ignore for Yaaic
#
# Android Studio & Gradle
*.iml
build/
.gradle/
.idea/
# Compiled and generated files
bin/
gen/
R.java
# Build files
local.properties
ant.properties
build.xml
proguard.cfg
# Maven
target/

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Yaaic</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

12
.travis.yml Normal file
View File

@ -0,0 +1,12 @@
language: android
android:
components:
- platform-tools
- tools
- build-tools-22.0.0
- android-22
- extra-google-google_play_services
- extra-google-m2repository
- extra-android-m2repository
notifications:
irc: "irc.freenode.net#yaaic"

View File

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.yaaic"
android:versionCode="6"
android:versionName="0.5">
<application
android:icon="@drawable/icon"
android:label="Yaaic">
<activity
android:name=".activity.ServersActivity"
android:label="@string/app_name"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.AddServerActivity"
android:label="@string/add_server_label">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="irc"/>
</intent-filter>
</activity>
<activity
android:name=".activity.ConversationActivity"
android:windowSoftInputMode="adjustResize|stateHidden">
</activity>
<activity
android:name=".activity.AboutActivity"
android:label="@string/about_label"
android:theme="@android:style/Theme.Dialog">
</activity>
<activity
android:name=".activity.SettingsActivity"
android:label="@string/settings_label">
</activity>
<activity
android:name=".activity.JoinActivity"
android:label="@string/join_label"
android:theme="@android:style/Theme.Dialog">
</activity>
<activity
android:name=".activity.UsersActivity"
android:label="@string/users"
android:theme="@android:style/Theme.Dialog">
</activity>
<activity
android:name=".activity.AddChannelActivity"
android:theme="@android:style/Theme.Dialog">
</activity>
<activity
android:name=".activity.AddCommandsActivity"
android:theme="@android:style/Theme.Dialog">
</activity>
<activity
android:name=".activity.MessageActivity"
android:theme="@android:style/Theme.Dialog">
</activity>
<activity
android:name=".activity.UserActivity"
android:theme="@android:style/Theme.Dialog">
</activity>
<service android:name=".irc.IRCService"></service>
</application>
<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>

261
CHANGELOG Normal file
View File

@ -0,0 +1,261 @@
--------------------------------------------------------------------------------
Yaaic 1.1 - 2015-03-17 - 55 commits, 707 files changed, 4 authors
--------------------------------------------------------------------------------
* Android 5.0 only (First preparations for a Material theme)
* You can finally scroll and it won't scroll back when someone writes something
* Fixed annoying bug that caused keyboard not showing up
* Forward slashes are now allowed in an Ident
* Support for LED light notification on nickname highlight
* Option to show seconds in timestamp
--------------------------------------------------------------------------------
Yaaic 1.0 - 2012-07-29 - 89 commits, 685 files changed, 7 authors
--------------------------------------------------------------------------------
* New cleaned up UI using ActionBar and ViewPager.
* Yaaic can now be installed on SD cards.
* New Android emoticons.
* New command: /back - Turns off the away status (Francesco Lavra)
* Several bug fixes
* Updated translations - Help translating Yaaic online:
http://crowdin.net/project/yaaic
--------------------------------------------------------------------------------
Yaaic 0.9 - 2011-07-17 - 67 commits, 49 files changed, 7 authors
--------------------------------------------------------------------------------
* SASL support (pocmo)
* Fullscreen chat setting (reyncor)
* Extended IRC URI support (reyncor)
* GUI for adding authentication data for Nickserv/SASL (pocmo)
* Only hide MOTD once (dsalt)
* Ignore status characters in front of nicks for the purpose of nick
completion (rasher)
* Configurable history size (Steven Luo)
* Overhaul notifications system (Steven Luo)
* Now displays the number of mentions that the user has not seen in the
notification.
* When no mentions are outstanding, display which servers the user is
connected to, not the last message.
* When more than one mention is outstanding, display the names of the
conversations with new mentions, not just the last message received.
* Notifications of mentions are suppressed if you're in the conversation
at the time of the mention.
* Notifications of mentions automatically clear when you bring up the
conversation.
* Vibrate notifications now generate the user's chosen default vibrate
pattern, not a hard-coded one.
* Add ticker text to the notification that's displayed when the IRCService
goes into the foreground, instead of displaying a blank ticker.
* Include channel topic in the displayed conversation title (Steven Luo)
* Actually deliver actions to existing private message windows (Steven Luo)
* Notify the user on receipt of all private messages, not just ones with nick
mentions. (Steven Luo)
* Ensure privmsg with mention of user's nick opens new query when appropriate
(Steven Luo)
* Remembers which conversation was last selected (Steven Luo)
* Danish translation (rasher)
--------------------------------------------------------------------------------
Yaaic 0.8 - 2011-03-15 - 27 commits, 35 files changed
--------------------------------------------------------------------------------
* Support for mIRC colors (liato)
* Support for graphical smilies (liato)
* Bugfix: Connection issues when nickname already in use (pocmo)
* Bugfix: Only automatically change nickname on server code 433 if not already
registered with server (pocmo)
* Turkish translation (Hasan Kiran)
* Several bugs fixed regarding force closes (pocmo)
* On own nick change: Display message in server info window (pocmo)
--------------------------------------------------------------------------------
Yaaic 0.7 - 2011-03-27 - 79 commits, 144 files changed
--------------------------------------------------------------------------------
* New setting: Play notification sound on highlight.
* Updated Robotium to 2.0.2
* All current scenario tests are now running
* Ident: Added "-" to the list of allowed characters
* Fixed voice recognition (Only add top match to the text input)
* Code cleanup and eclipse code formatter settings
* New translation: Italian (Thanks to Gianmarco Laggia!)
* Minimum width defined for some buttons that may become difficult to touch
* A lot of code cleanup (mostly formatting)
* New user action view and new actions: reply, query
* Fixed typo: "joines" -> "joins"
* Fixed some issues in the IRC parser for bouncers. Especially regarding
Irsii proxy.
* Tablet support. Yaaic will scale to different screen resolutions.
* Tweak some nick colors for readability on Yaaic's dark background. (kugel-)
* Reduce sensitivity of channel switcher (kugel-)
* Always open last activity and do not start with server list (liato & kugel-)
* Resolved a lot of connection issues - especially with bouncers.
* Some improvements for accessibility (but still a lot of things to do)
* All dimensions and fontsizes now use screen independent sizes and should
therefore look better on differen screen sizes.
* It's now possible to hide quit messages as well.
* New Setting: Show notices in server window
--------------------------------------------------------------------------------
Yaaic 0.6.1 - 2010-12-17 - 15 commits, 109 files changed
--------------------------------------------------------------------------------
* Fixed a bug in the french and spanish translation that may cause force closes
on connecting to a server.
* New setting available: Hide join and part messages.
* Automated testing: Some first scenario tests using the Robotium framework.
* Improved nickname detection: Words including the nickname won't cause a
highlight. (Thanks to liato!)
* Vibrating on highlight is now available as a setting. (Thanks to liato!)
--------------------------------------------------------------------------------
Yaaic 0.6 - 2010-11-16 - 80 commits, 179 files changed
--------------------------------------------------------------------------------
* Voice recognition via Google API
* Everything is now easy translatable via one XML file
* Customizable font sizes (8px - 20px)
* New shortcut: /w for /whois
* Every unknown command will now be sent to the server. No more command
whitelisting.
* Colored nicknames (by chantra)
* Set a list of nickname aliases (by ZoogieZork)
* Small ruby script to check the translation status
* Userlist is now sorted alphabetically (By mloskot)
* Nick completion via search button - completes current selection or at the
cursor position (Patch by Thomas Martitz)
* Build files for ant
* Merged yaaic application and testing repositories
* First scenario tests via the robotium lib.
* Translations:
o Chinese
o Japanese (work in progress)
o German (work in progress)
o French
o Spanish
--------------------------------------------------------------------------------
Yaaic 0.5 - 2010-08-27 - 35 commits, 19 files changed
--------------------------------------------------------------------------------
* Awesome channel indicator at the bottom of the screen showing highlights and
new messages in other channels
* Define a custom quit message in the settings menu
* Execute commands on connect BEFORE joining channels
* Wait a small amount of time before auto-joining channels (because of slow
server commands)
* Tap a nickname in the user list to perform an action (op, deop, kick, ...)
* Bugfix: Enter key did not work on Motorola Milestone
* Disable "Ok" button on Add Channel, Add Command dialogs until something's
actually been added or removed. (by brion. thanks!)
* Other small adjustments and bugfixes
* Bugfix: The ident now can contain numbers
* Bugfix: Nicknames now can start with an underscore (_)
--------------------------------------------------------------------------------
Yaaic 0.4.1 - 2010-04-27 - 14 commits, 13 files changed
--------------------------------------------------------------------------------
* When using the reconnect feature (Settings) - Yaaic sometimes did reconnect
even when you disconnected yourself (even when "exit" was used)
--------------------------------------------------------------------------------
Yaaic 0.4 - 2010-04-25 - 66 commits, 36 files changed
--------------------------------------------------------------------------------
* You can now define channels to join after connecting to a server
* It's also possible now to add commands that are executed after connecting to
a server
* When adding/editing a server spaces at the beginning and ending will be
removed due to some "on screen keyboards" adding spaces.
* The following server commands have been added to the whitelist and Yaaic will
now send them to the server: /opper, /nickserv, /ns, /chanserv, /cs,
/authserv, /hostserv, /memoserv, /operserv
* Bugfix: Closed queries couldn't be reopened when closed
* New command: Send a message to a channel or user:
/msg <target> <message> (See Issue 10)
* New command: Send a message to all channels on the server: /amsg <message>
* Bugfix: Nicknames can now contain a hyphen (-) (See issue 9)
* Bugfix: When using BIP IRC Proxy channels were not joined (See Issue 8)
* New command: /quote <line> or /raw <line> to send a raw line to the server
* Settings: You can now enable to reconnect automatically on disconnect
* Bugfix: Sometimes the notification icon was still in the notification bar if
not connected to any server and yaaic not running
* The menu now contains an "exit" option to disconnect from all servers and
exiting Yaaic.
* Bugfix: When selection "connect" via long-click on a connected server in the
list, Yaaic disconnected.
* The /help command now shows the usage of a command if given as parameter:
/help <command> (Thanks to Kell)
* The server list now also shows the nickname and the port of the server
--------------------------------------------------------------------------------
Yaaic 0.3 - 2010-04-15 - 145 commits, 79 files changed.
--------------------------------------------------------------------------------
* Yaaic now has an awesome icon designed by androidicons.com
* It's now possible to select a charset when adding/editing a server. See the
list of supported charsets for more details.
* SSL-Support! You are now able to use SSL connections with Yaaic. But beware!
The current TrustManager will accept every certificate.
* There will be an icon in your notification bar if you are connected to a
server.
* You can now connect to some IRC networks that use strange spam bot checks.
* The background service is now persistent so that you don't get disconnected
while yaaic is in the background and you are using an other app.
* Bugfix: Sometimes the app crashed if you disconnected from a server and
connected again to the same server later.
* There has been a lot of code optimization. Hopefully Yaaic is now much more
smoother.
* You are now notified about a disconnect in all conversation views.
* The background color is now fixed so that Yaaic should look the same on
Android 1.5 as well as on Android 2.x.
* There's now a menu option to show a list of the users in the current selected
channel
* Highlights (if someone mentions your nickname), Connects and Disconnects are
now shown as notifications in the notification bar.
* You can now use the dialpad up and dialpad down buttons to scroll in the
history of messages entered by you
* Menu items that are not ussable until connect are now inactive.
* There's now a /help command showing all commands available (Thanks to Kell)
* If a disconnect occurs Yaaic will now ask you if you want to reconnect
(Currently only if yaaic is not in the background)
* Developers: There's now a second repository for automated testing with some
unit tests already added: http://github.com/pocmo/Yaaic-Test
* Bugfix: The timestamps sometimes were wrong, especially the timestamps in
12h format were totally wrong at all
* New commands handled by the client: /away /whois
* Last but not least, thanks to tkn for contributing a bug fix! :)
--------------------------------------------------------------------------------
Yaaic 0.2 - 2010-03-20 - 58 commits, 22 files changed.
--------------------------------------------------------------------------------
* Bugfix: Fixed an annoying bug that caused messages to sometimes appear in the
wrong channel / query
* Bugfix: A lot of (visual) issues have been fixed when using the on screen
keyboard
* More IRC events are now shown as messages:
* On set / remove channel key
* On set / remove channel secret
* On set / remove channel ban
* On set / remove channel limit
* On set / remove topic protection
* On set / remove external messages
* On set / remove invite only
* On set / remove moderated
* On set / remove private
* On invite into channel
* Send files via DCC with /dcc SEND <nickname> <file>
* The join channel dialog is now permanent and does not disappear on rotation
* It's now mandatory to enter a real name as servers require a value on connect
* A nicer look and feel with transcluent conversation windows and rounded
corners
* Bugfix: Scrollbar didn't scroll automatically sometimes
* Bugfix: Messages updated their timestamp when application was resumed
* Server responses are now shown in the server info window (some are skipped)
* Messages containing the current nickname are now highlighted (red color)
* If you are clicking on an irc:// link in the browser you are now able to add
this server to your server list
* Servers in the serverlist can now be edited (long touch a server)
* UTF-8 is now the default enconding used by the IRC client. There will be an
option to choose an enconding in a future release
* Bugfix: Messages that have been written by users while the client was paused
didn't appear directly on resume
* Server titles now have to be unique
* ... some other small fixes and adjustments
--------------------------------------------------------------------------------
Yaaic 0.1 (Beta) - 2010-03-14
--------------------------------------------------------------------------------
* This is the first release. There hasn't changed anything to prior releases ;)

41
CONTRIBUTORS Normal file
View File

@ -0,0 +1,41 @@
Thanks to all contributors!
--------------------------------------------------------------------------------
Development
--------------------------------------------------------------------------------
Sebastian Kaspari https://github.com/pocmo
Karol Gliniecki https://github.com/kell
Michael Imamura https://github.com/ZoogieZork
Liato https://github.com/liato
Chantra https://github.com/chantra
Torben Nielsen https://github.com/tkn
Brion Vibber https://github.com/brion
Thomas Martitz https://github.com/kugel-
Mateusz Loskot https://github.com/mloskot
Steven Luo
Jonas Häggqvist https://github.com/rasher
Reyncor https://github.com/Reyncor
Darren Salt https://github.com/dsalt
Daniel E. Moctezuma https://github.com/democtezuma
--------------------------------------------------------------------------------
Graphics
--------------------------------------------------------------------------------
Guenther Beyer http://www.androidicons.com
Jörn Schreiber http://www.joern-schreiber.de
--------------------------------------------------------------------------------
Translations
--------------------------------------------------------------------------------
English Sebastian Kaspari https://github.com/pocmo
Spanish Diego Kuperman https://github.com/diegok
German Daniel Bonkowski
Italian Gianmarco Laggia
French Remi Rampin https://github.com/remram44
Japanese Nobuhiro Ito https://github.com/iseebi
Daniel E. Moctezuma https://github.com/democtezuma
Chinese Leekie (江珑)
Turkish Hasan Kiran
Danish Jonas Häggqvist https://github.com/rasher
Russian NeKit

View File

44
README
View File

@ -1,44 +0,0 @@
Yaaic - Yet Another Android IRC Client
--------------------------------------------------------------------
This is the source code distribution of Yaaic. If you are looking
for a compiled 'ready to use' version, see the official homepage at:
http://www.yaaic.org
If you are a developer and want to contribute to Yaaic, checkout
our repository at github:
http://github.com/pocmo/Yaaic
See also the "test package" for unit tests & co.:
http://github.com/pocmo/Yaaic-Test
--------------------------------------------------------------------
Yaaic includes the PircBot IRC API written by Paul Mutton available
under the GNU General Public License (GPL). http://www.jibble.org
The Yaaic icon was designed by http://www.androidicons.com
Some icons are part of the Silk icon set designed by Mark James
available under the Creative Commons Licence Attribution 3.0
Licence. http://www.famfamfam.com
--------------------------------------------------------------------
Yaaic 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.
Yaaic 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 Yaaic. If not, see http://www.gnu.org/licenses/

61
README.md Normal file
View File

@ -0,0 +1,61 @@
[![Build Status](https://travis-ci.org/pocmo/Yaaic.svg?branch=master)](https://travis-ci.org/pocmo/Yaaic)
Yaaic - Yet Another Android IRC Client
======================================
Yaaic is as the full name already says an Internet Relay Chat (IRC)
client for Android devices.
This is the source code distribution of Yaaic. If you are looking
for a compiled 'ready to use' version (APK), get the official
build at the Google Play Store:
* https://play.google.com/store/apps/details?id=org.yaaic
If you are a developer and want to contribute to Yaaic, checkout
our repository at GitHub:
* http://github.com/pocmo/Yaaic
The project is using Gradle to build the application. Importing it
into Android Studio should be enough to get it building.
Drop me a line for questions regarding Yaaic or use one of the
following resources:
- IRC: irc.freenode.net #yaaic
- Homepage: http://www.yaaic.org
- Google Group: http://groups.google.com/group/yaaic
- Twitter: http://twitter.com/Yaaic
- Facebook: http://www.facebook.com/pages/Yaaic/359902798214
Third party libraries & resources
-----------------------------------------------------------------------
Yaaic includes the PircBot IRC API written by Paul Mutton available
under the GNU General Public License (GPL). http://www.jibble.org
The Yaaic icon was designed by http://www.androidicons.com
Some icons are part of the Silk icon set designed by Mark James
available under the Creative Commons Licence Attribution 3.0
Licence. http://www.famfamfam.com
Copyright (GPL)
-----------------------------------------------------------------------
Copyright 2009-2015 Sebastian Kaspari
Yaaic 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.
Yaaic 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 Yaaic. If not, see http://www.gnu.org/licenses/

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

32
app/build.gradle Normal file
View File

@ -0,0 +1,32 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion '22.0.0'
defaultConfig {
applicationId "org.yaaic"
minSdkVersion 21
targetSdkVersion 22
versionCode 14
versionName "2.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
// A warning inside of appcompat prevents us from enabling this option
abortOnError false
}
}
dependencies {
compile 'com.android.support:support-v4:22.1.1'
compile 'com.android.support:cardview-v7:22.1.1'
compile 'com.android.support:recyclerview-v7:22.1.1'
compile 'com.android.support:appcompat-v7:22.1.1'
}

17
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Applications/Android-SDK/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.yaaic"
android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:icon="@mipmap/ic_launcher"
android:label="Yaaic"
android:theme="@style/Theme.Yaaic"
android:allowBackup="true"
android:name=".YaaicApplication">
<activity android:name=".activity.MainActivity"
android:label="@string/app_name"
android:launchMode="standard" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".activity.AddServerActivity"
android:label="@string/add_server_label" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="irc" />
</intent-filter>
</activity>
<activity
android:name=".activity.AboutActivity"
android:label="@string/about_label"
android:theme="@android:style/Theme.Material.Dialog" >
</activity>
<activity
android:name=".activity.JoinActivity"
android:label="@string/join_label"
android:theme="@android:style/Theme.Material.Dialog" >
</activity>
<activity
android:name=".activity.UsersActivity"
android:label="@string/users"
android:theme="@android:style/Theme.Material.Dialog" >
</activity>
<activity
android:name=".activity.AddAliasActivity"
android:theme="@android:style/Theme.Dialog" >
</activity>
<activity
android:name=".activity.AddChannelActivity"
android:theme="@android:style/Theme.Material.Dialog" >
</activity>
<activity
android:name=".activity.AddCommandsActivity"
android:theme="@android:style/Theme.Material.Dialog" >
</activity>
<activity
android:name=".activity.MessageActivity"
android:theme="@android:style/Theme.Material.Dialog" >
</activity>
<activity
android:name=".activity.UserActivity"
android:theme="@android:style/Theme.Material.Dialog" >
</activity>
<activity
android:name=".activity.AuthenticationActivity"
android:theme="@android:style/Theme.Material.Dialog" >
</activity>
<service android:name=".irc.IRCService" >
</service>
</application>
</manifest>

View File

@ -22,9 +22,9 @@ package org.jibble.pircbot;
* @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007)
*/
public class IrcException extends Exception {
private static final long serialVersionUID = -3705541066912475928L;
private static final long serialVersionUID = -3705541066912475928L;
/**
/**
* Constructs a new IrcException.
*
* @param e The error message to report.

View File

@ -25,9 +25,9 @@ package org.jibble.pircbot;
* @version 1.4.6 (Build time: Wed Apr 11 19:20:59 2007)
*/
public class NickAlreadyInUseException extends IrcException {
private static final long serialVersionUID = -4724325464519465479L;
private static final long serialVersionUID = -4724325464519465479L;
/**
/**
* Constructs a new IrcException.
*
* @param e The error message to report.

View File

@ -0,0 +1,137 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import org.yaaic.db.Database;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Global Master Class :)
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class Yaaic
{
public static Yaaic instance;
private HashMap<Integer, Server> servers;
private boolean serversLoaded = false;
/**
* Private constructor, you may want to use static getInstance()
*/
private Yaaic()
{
servers = new HashMap<Integer, Server>();
}
/**
* Load servers from database
*
* @param context
*/
public void loadServers(Context context)
{
if (!serversLoaded) {
Database db = new Database(context);
servers = db.getServers();
db.close();
// context.sendBroadcast(new Intent(Broadcast.SERVER_UPDATE));
serversLoaded = true;
}
}
/**
* Get global Yaaic instance
*
* @return the global Yaaic instance
*/
public static Yaaic getInstance()
{
if (instance == null) {
instance = new Yaaic();
}
return instance;
}
/**
* Get server by id
*
* @return Server object with given unique id
*/
public Server getServerById(int serverId)
{
return servers.get(serverId);
}
/**
* Remove server with given unique id from list
*
* @param serverId
*/
public void removeServerById(int serverId)
{
servers.remove(serverId);
}
/**
* Add server to list
*/
public void addServer(Server server)
{
if (!servers.containsKey(server.getId())) {
servers.put(server.getId(), server);
}
}
/**
* Update a server in list
*/
public void updateServer(Server server)
{
servers.put(server.getId(), server);
}
/**
* Get list of servers
*
* @return list of servers
*/
public ArrayList<Server> getServersAsArrayList()
{
ArrayList<Server> serverList = new ArrayList<Server>();
Set<Integer> mKeys = servers.keySet();
for (int key : mKeys) {
serverList.add(servers.get(key));
}
return serverList;
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -18,11 +18,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.listener;
package org.yaaic;
public interface ConversationListener
{
public void onConversationMessage(String target);
public void onNewConversation(String target);
public void onRemoveConversation(String target);
import android.app.Application;
/**
* Application implementation for Yaaic.
*/
public class YaaicApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Yaaic.getInstance().loadServers(this);
}
}

View File

@ -0,0 +1,72 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2015 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.TextView;
import org.yaaic.R;
/**
* "About" dialog activity.
*/
public class AboutActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.about);
initializeVersionView();
initializeIrcView();
}
private void initializeVersionView() {
try {
TextView versionView = (TextView) findViewById(R.id.version);
versionView.setText(
getPackageManager().getPackageInfo(getPackageName(), 0).versionName
);
} catch (PackageManager.NameNotFoundException e) {
throw new AssertionError("Should not happen: Can't read application info of myself");
}
}
private void initializeIrcView() {
TextView ircLinkView = (TextView) findViewById(R.id.about_irclink);
ircLinkView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(AboutActivity.this, AddServerActivity.class);
intent.setData(Uri.parse(getString(R.string.app_irc)));
startActivity(intent);
}
});
}
}

View File

@ -0,0 +1,149 @@
package org.yaaic.activity;
import java.util.ArrayList;
import org.yaaic.R;
import org.yaaic.model.Extra;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
public class AddAliasActivity extends Activity implements OnClickListener, OnItemClickListener, TextWatcher
{
private EditText aliasInput;
private ArrayAdapter<String> adapter;
private ArrayList<String> aliases;
private Button addButton;
private Button okButton;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.aliasadd);
aliasInput = (EditText) findViewById(R.id.alias);
aliasInput.addTextChangedListener(this);
adapter = new ArrayAdapter<String>(this, R.layout.aliasitem);
ListView list = (ListView) findViewById(R.id.aliases);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
addButton = (Button) findViewById(R.id.add);
addButton.setOnClickListener(this);
((Button) findViewById(R.id.cancel)).setOnClickListener(this);
okButton = (Button) findViewById(R.id.ok);
okButton.setOnClickListener(this);
okButton.setEnabled(false);
aliases = getIntent().getExtras().getStringArrayList(Extra.ALIASES);
for (String alias : aliases) {
adapter.add(alias);
}
}
/**
* On Click
*/
@Override
public void onClick(View v)
{
switch (v.getId()) {
case R.id.add:
String alias = aliasInput.getText().toString().trim();
aliases.add(alias);
adapter.add(alias);
aliasInput.setText("");
okButton.setEnabled(true);
break;
case R.id.cancel:
setResult(RESULT_CANCELED);
finish();
break;
case R.id.ok:
// Get list and return as result
Intent intent = new Intent();
intent.putExtra(Extra.ALIASES, aliases);
setResult(RESULT_OK, intent);
finish();
break;
}
}
/**
* On item clicked
*/
@Override
public void onItemClick(AdapterView<?> list, View item, int position, long id)
{
final String alias = adapter.getItem(position);
String[] items = { getResources().getString(R.string.action_remove) };
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(alias);
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
switch (item) {
case 0: // Remove
adapter.remove(alias);
aliases.remove(alias);
okButton.setEnabled(true);
break;
}
}
});
AlertDialog alert = builder.create();
alert.show();
}
/**
* On text changed
*/
@Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
addButton.setEnabled(aliasInput.getText().length() > 0);
}
/**
* After text changed
*/
@Override
public void afterTextChanged(Editable s)
{
// Do nothing.
}
/**
* Before text changed
*/
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after)
{
// Do nothing.
}
}

View File

@ -0,0 +1,147 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import java.util.ArrayList;
import org.yaaic.R;
import org.yaaic.model.Extra;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
/**
* Adding auto join channels to a server
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class AddChannelActivity extends Activity implements OnClickListener, OnItemClickListener
{
private EditText channelInput;
private ArrayAdapter<String> adapter;
private ArrayList<String> channels;
private Button okButton;
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.channeladd);
channelInput = (EditText) findViewById(R.id.channel);
channelInput.setSelection(1);
adapter = new ArrayAdapter<String>(this, R.layout.channelitem);
ListView list = (ListView) findViewById(R.id.channels);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
((Button) findViewById(R.id.add)).setOnClickListener(this);
((Button) findViewById(R.id.cancel)).setOnClickListener(this);
okButton = (Button) findViewById(R.id.ok);
okButton.setOnClickListener(this);
okButton.setEnabled(false);
channels = getIntent().getExtras().getStringArrayList(Extra.CHANNELS);
for (String channel : channels) {
adapter.add(channel);
}
}
/**
* On Click
*/
@Override
public void onClick(View v)
{
switch (v.getId()) {
case R.id.add:
String channel = channelInput.getText().toString().trim();
channels.add(channel);
adapter.add(channel);
channelInput.setText("#");
channelInput.setSelection(1);
okButton.setEnabled(true);
break;
case R.id.cancel:
setResult(RESULT_CANCELED);
finish();
break;
case R.id.ok:
// Get list and return as result
Intent intent = new Intent();
intent.putExtra(Extra.CHANNELS, channels);
setResult(RESULT_OK, intent);
finish();
break;
}
}
/**
* On item clicked
*/
@Override
public void onItemClick(AdapterView<?> list, View item, int position, long id)
{
final String channel = adapter.getItem(position);
String[] items = { getResources().getString(R.string.action_remove) };
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(channel);
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
switch (item) {
case 0: // Remove
adapter.remove(channel);
channels.remove(channel);
okButton.setEnabled(true);
break;
}
}
});
AlertDialog alert = builder.create();
alert.show();
}
}

View File

@ -0,0 +1,151 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import java.util.ArrayList;
import org.yaaic.R;
import org.yaaic.model.Extra;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
/**
* Adding commands (to execute after connect) to a server
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class AddCommandsActivity extends Activity implements OnClickListener, OnItemClickListener
{
private EditText commandInput;
private ArrayAdapter<String> adapter;
private ArrayList<String> commands;
private Button okButton;
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.commandadd);
commandInput = (EditText) findViewById(R.id.command);
adapter = new ArrayAdapter<String>(this, R.layout.commanditem);
ListView list = (ListView) findViewById(R.id.commands);
list.setAdapter(adapter);
list.setOnItemClickListener(this);
((Button) findViewById(R.id.add)).setOnClickListener(this);
((Button) findViewById(R.id.ok)).setOnClickListener(this);
((Button) findViewById(R.id.cancel)).setOnClickListener(this);
okButton = (Button) findViewById(R.id.ok);
okButton.setOnClickListener(this);
okButton.setEnabled(false);
commands = getIntent().getExtras().getStringArrayList(Extra.COMMANDS);
for (String command : commands) {
adapter.add(command);
}
}
/**
* On Click
*/
@Override
public void onClick(View v)
{
switch (v.getId()) {
case R.id.add:
String command = commandInput.getText().toString().trim();
if (!command.startsWith("/")) {
command = "/" + command;
}
commands.add(command);
adapter.add(command);
commandInput.setText("/");
okButton.setEnabled(true);
break;
case R.id.cancel:
setResult(RESULT_CANCELED);
finish();
break;
case R.id.ok:
// Get list and return as result
Intent intent = new Intent();
intent.putExtra(Extra.COMMANDS, commands);
setResult(RESULT_OK, intent);
finish();
break;
}
}
/**
* On item clicked
*/
@Override
public void onItemClick(AdapterView<?> list, View item, int position, long id)
{
final String command = adapter.getItem(position);
String[] items = { getResources().getString(R.string.action_remove) };
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(command);
builder.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int item) {
switch (item) {
case 0: // Remove
adapter.remove(command);
commands.remove(command);
okButton.setEnabled(true);
break;
}
}
});
AlertDialog alert = builder.create();
alert.show();
}
}

View File

@ -0,0 +1,453 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;
import org.yaaic.R;
import org.yaaic.Yaaic;
import org.yaaic.db.Database;
import org.yaaic.exception.ValidationException;
import org.yaaic.model.Authentication;
import org.yaaic.model.Extra;
import org.yaaic.model.Identity;
import org.yaaic.model.Server;
import org.yaaic.model.Status;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.regex.Pattern;
/**
* Add a new server to the list
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class AddServerActivity extends ActionBarActivity implements OnClickListener
{
private static final int REQUEST_CODE_CHANNELS = 1;
private static final int REQUEST_CODE_COMMANDS = 2;
private static final int REQUEST_CODE_ALIASES = 3;
private static final int REQUEST_CODE_AUTHENTICATION = 4;
private Server server;
private Authentication authentication;
private ArrayList<String> aliases;
private ArrayList<String> channels;
private ArrayList<String> commands;
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_server);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.addView(LayoutInflater.from(this).inflate(R.layout.item_done_discard, toolbar, false));
setSupportActionBar(toolbar);
authentication = new Authentication();
aliases = new ArrayList<String>();
channels = new ArrayList<String>();
commands = new ArrayList<String>();
findViewById(R.id.aliases).setOnClickListener(this);
findViewById(R.id.channels).setOnClickListener(this);
findViewById(R.id.commands).setOnClickListener(this);
findViewById(R.id.authentication).setOnClickListener(this);
Spinner spinner = (Spinner) findViewById(R.id.charset);
String[] charsets = getResources().getStringArray(R.array.charsets);
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, charsets);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
Bundle extras = getIntent().getExtras();
if (extras != null && extras.containsKey(Extra.SERVER)) {
setTitle(R.string.edit_server_label);
// Request to edit an existing server
Database db = new Database(this);
this.server = db.getServerById(extras.getInt(Extra.SERVER));
aliases.addAll(server.getIdentity().getAliases());
this.channels = db.getChannelsByServerId(server.getId());
this.commands = db.getCommandsByServerId(server.getId());
this.authentication = server.getAuthentication();
db.close();
// Set server values
((EditText) findViewById(R.id.title)).setText(server.getTitle());
((EditText) findViewById(R.id.host)).setText(server.getHost());
((EditText) findViewById(R.id.port)).setText(String.valueOf(server.getPort()));
((EditText) findViewById(R.id.password)).setText(server.getPassword());
((EditText) findViewById(R.id.nickname)).setText(server.getIdentity().getNickname());
((EditText) findViewById(R.id.ident)).setText(server.getIdentity().getIdent());
((EditText) findViewById(R.id.realname)).setText(server.getIdentity().getRealName());
((CheckBox) findViewById(R.id.useSSL)).setChecked(server.useSSL());
// Select charset
if (server.getCharset() != null) {
for (int i = 0; i < charsets.length; i++) {
if (server.getCharset().equals(charsets[i])) {
spinner.setSelection(i);
break;
}
}
}
}
// Disable suggestions for host name
if (android.os.Build.VERSION.SDK_INT >= 5) {
EditText serverHostname = (EditText) findViewById(R.id.host);
serverHostname.setInputType(0x80000);
}
Uri uri = getIntent().getData();
if (uri != null && uri.getScheme().equals("irc")) {
// handling an irc:// uri
((EditText) findViewById(R.id.host)).setText(uri.getHost());
if (uri.getPort() != -1) {
((EditText) findViewById(R.id.port)).setText(String.valueOf(uri.getPort()));
}
if (uri.getPath() != null) {
channels.add(uri.getPath().replace('/', '#'));
}
if (uri.getQuery() != null) {
((EditText) findViewById(R.id.password)).setText(String.valueOf(uri.getQuery()));
}
}
}
/**
* On activity result
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode != RESULT_OK) {
return; // ignore everything else
}
switch (requestCode) {
case REQUEST_CODE_ALIASES:
aliases.clear();
aliases.addAll(data.getExtras().getStringArrayList(Extra.ALIASES));
break;
case REQUEST_CODE_CHANNELS:
channels = data.getExtras().getStringArrayList(Extra.CHANNELS);
break;
case REQUEST_CODE_COMMANDS:
commands = data.getExtras().getStringArrayList(Extra.COMMANDS);
break;
case REQUEST_CODE_AUTHENTICATION:
authentication.setSaslUsername(data.getExtras().getString(Extra.SASL_USER));
authentication.setSaslPassword(data.getExtras().getString(Extra.SASL_PASSWORD));
authentication.setNickservPassword(data.getExtras().getString(Extra.NICKSERV_PASSWORD));
break;
}
}
/**
* On click add server or cancel activity
*/
@Override
public void onClick(View v)
{
switch (v.getId()) {
case R.id.aliases:
Intent aliasIntent = new Intent(this, AddAliasActivity.class);
aliasIntent.putExtra(Extra.ALIASES, aliases);
startActivityForResult(aliasIntent, REQUEST_CODE_ALIASES);
break;
case R.id.authentication:
Intent authIntent = new Intent(this, AuthenticationActivity.class);
authIntent.putExtra(Extra.NICKSERV_PASSWORD, authentication.getNickservPassword());
authIntent.putExtra(Extra.SASL_USER, authentication.getSaslUsername());
authIntent.putExtra(Extra.SASL_PASSWORD, authentication.getSaslPassword());
startActivityForResult(authIntent, REQUEST_CODE_AUTHENTICATION);
break;
case R.id.channels:
Intent channelIntent = new Intent(this, AddChannelActivity.class);
channelIntent.putExtra(Extra.CHANNELS, channels);
startActivityForResult(channelIntent, REQUEST_CODE_CHANNELS);
break;
case R.id.commands:
Intent commandsIntent = new Intent(this, AddCommandsActivity.class);
commandsIntent.putExtra(Extra.COMMANDS, commands);
startActivityForResult(commandsIntent, REQUEST_CODE_COMMANDS);
break;
}
}
public void onCancel(View view) {
setResult(RESULT_CANCELED);
finish();
}
/**
* Try to save server.
*/
public void onSave(View view) {
try {
validateServer();
validateIdentity();
if (server == null) {
addServer();
} else {
updateServer();
}
setResult(RESULT_OK);
finish();
} catch(ValidationException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
/**
* Add server to database
*/
private void addServer()
{
Database db = new Database(this);
Identity identity = getIdentityFromView();
long identityId = db.addIdentity(
identity.getNickname(),
identity.getIdent(),
identity.getRealName(),
identity.getAliases()
);
Server server = getServerFromView();
server.setAuthentication(authentication);
long serverId = db.addServer(server, (int) identityId);
db.setChannels((int) serverId, channels);
db.setCommands((int) serverId, commands);
db.close();
server.setId((int) serverId);
server.setIdentity(identity);
server.setAutoJoinChannels(channels);
server.setConnectCommands(commands);
Yaaic.getInstance().addServer(server);
}
/**
* Update server
*/
private void updateServer()
{
Database db = new Database(this);
int serverId = this.server.getId();
int identityId = db.getIdentityIdByServerId(serverId);
Server server = getServerFromView();
server.setAuthentication(authentication);
db.updateServer(serverId, server, identityId);
Identity identity = getIdentityFromView();
db.updateIdentity(
identityId,
identity.getNickname(),
identity.getIdent(),
identity.getRealName(),
identity.getAliases()
);
db.setChannels(serverId, channels);
db.setCommands(serverId, commands);
db.close();
server.setId(this.server.getId());
server.setIdentity(identity);
server.setAutoJoinChannels(channels);
server.setConnectCommands(commands);
Yaaic.getInstance().updateServer(server);
}
/**
* Populate a server object from the data in the view
*
* @return The server object
*/
private Server getServerFromView()
{
String title = ((EditText) findViewById(R.id.title)).getText().toString().trim();
String host = ((EditText) findViewById(R.id.host)).getText().toString().trim();
int port = Integer.parseInt(((EditText) findViewById(R.id.port)).getText().toString().trim());
String password = ((EditText) findViewById(R.id.password)).getText().toString().trim();
String charset = ((Spinner) findViewById(R.id.charset)).getSelectedItem().toString();
Boolean useSSL = ((CheckBox) findViewById(R.id.useSSL)).isChecked();
// not in use yet
//boolean autoConnect = ((CheckBox) findViewById(R.id.autoconnect)).isChecked();
Server server = new Server();
server.setHost(host);
server.setPort(port);
server.setPassword(password);
server.setTitle(title);
server.setCharset(charset);
server.setUseSSL(useSSL);
server.setStatus(Status.DISCONNECTED);
return server;
}
/**
* Populate an identity object from the data in the view
*
* @return The identity object
*/
private Identity getIdentityFromView()
{
String nickname = ((EditText) findViewById(R.id.nickname)).getText().toString().trim();
String ident = ((EditText) findViewById(R.id.ident)).getText().toString().trim();
String realname = ((EditText) findViewById(R.id.realname)).getText().toString().trim();
Identity identity = new Identity();
identity.setNickname(nickname);
identity.setIdent(ident);
identity.setRealName(realname);
identity.setAliases(aliases);
return identity;
}
/**
* Validate the input for a server
*
* @throws ValidationException
*/
private void validateServer() throws ValidationException
{
String title = ((EditText) findViewById(R.id.title)).getText().toString();
String host = ((EditText) findViewById(R.id.host)).getText().toString();
String port = ((EditText) findViewById(R.id.port)).getText().toString();
String charset = ((Spinner) findViewById(R.id.charset)).getSelectedItem().toString();
if (title.trim().equals("")) {
throw new ValidationException(getResources().getString(R.string.validation_blank_title));
}
if (host.trim().equals("")) {
// XXX: We should use some better host validation
throw new ValidationException(getResources().getString(R.string.validation_blank_host));
}
try {
Integer.parseInt(port);
} catch (NumberFormatException e) {
throw new ValidationException(getResources().getString(R.string.validation_invalid_port));
}
try {
"".getBytes(charset);
}
catch (UnsupportedEncodingException e) {
throw new ValidationException(getResources().getString(R.string.validation_unsupported_charset));
}
Database db = new Database(this);
if (db.isTitleUsed(title) && (server == null || !server.getTitle().equals(title))) {
db.close();
throw new ValidationException(getResources().getString(R.string.validation_title_used));
}
db.close();
}
/**
* Validate the input for a identity
*
* @throws ValidationException
*/
private void validateIdentity() throws ValidationException
{
String nickname = ((EditText) findViewById(R.id.nickname)).getText().toString();
String ident = ((EditText) findViewById(R.id.ident)).getText().toString();
String realname = ((EditText) findViewById(R.id.realname)).getText().toString();
if (nickname.trim().equals("")) {
throw new ValidationException(getResources().getString(R.string.validation_blank_nickname));
}
if (ident.trim().equals("")) {
throw new ValidationException(getResources().getString(R.string.validation_blank_ident));
}
if (realname.trim().equals("")) {
throw new ValidationException(getResources().getString(R.string.validation_blank_realname));
}
// RFC 1459: <nick> ::= <letter> { <letter> | <number> | <special> }
// <special> ::= '-' | '[' | ']' | '\' | '`' | '^' | '{' | '}'
// Chars that are not in RFC 1459 but are supported too:
// | and _
Pattern nickPattern = Pattern.compile("^[a-zA-Z_][a-zA-Z0-9^\\-`\\[\\]{}|_\\\\]*$");
if (!nickPattern.matcher(nickname).matches()) {
throw new ValidationException(getResources().getString(R.string.validation_invalid_nickname));
}
// We currently only allow chars, numbers and some special chars for ident
Pattern identPattern = Pattern.compile("^[a-zA-Z0-9\\[\\]\\-_/]+$");
if (!identPattern.matcher(ident).matches()) {
throw new ValidationException(getResources().getString(R.string.validation_invalid_ident));
}
}
}

View File

@ -0,0 +1,159 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import org.yaaic.R;
import org.yaaic.model.Extra;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.CompoundButton.OnCheckedChangeListener;
/**
* Authentication activity for entering nickserv / sasl usernames and password
* for a given server.
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class AuthenticationActivity extends Activity implements OnCheckedChangeListener, OnClickListener
{
private CheckBox nickservCheckbox;
private TextView nickservPasswordLabel;
private EditText nickservPasswordEditText;
private CheckBox saslCheckbox;
private TextView saslUsernameLabel;
private EditText saslUsernameEditText;
private TextView saslPasswordLabel;
private EditText saslPasswordEditText;
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.authentication);
nickservCheckbox = (CheckBox) findViewById(R.id.nickserv_checkbox);
nickservPasswordLabel = (TextView) findViewById(R.id.nickserv_label_password);
nickservPasswordEditText = (EditText) findViewById(R.id.nickserv_password);
saslCheckbox = (CheckBox) findViewById(R.id.sasl_checkbox);
saslUsernameLabel = (TextView) findViewById(R.id.sasl_label_username);
saslUsernameEditText = (EditText) findViewById(R.id.sasl_username);
saslPasswordLabel = (TextView) findViewById(R.id.sasl_label_password);
saslPasswordEditText = (EditText) findViewById(R.id.sasl_password);
nickservCheckbox.setOnCheckedChangeListener(this);
saslCheckbox.setOnCheckedChangeListener(this);
Bundle extras = getIntent().getExtras();
if (extras != null) {
String nickservPassword = extras.getString(Extra.NICKSERV_PASSWORD);
if (nickservPassword != null && nickservPassword.length() > 0) {
nickservCheckbox.setChecked(true);
nickservPasswordEditText.setText(nickservPassword);
}
String saslUsername = extras.getString(Extra.SASL_USER);
String saslPassword = extras.getString(Extra.SASL_PASSWORD);
if (saslUsername != null && saslUsername.length() > 0) {
saslCheckbox.setChecked(true);
saslUsernameEditText.setText(saslUsername);
saslPasswordEditText.setText(saslPassword);
}
}
((Button) findViewById(R.id.ok)).setOnClickListener(this);
((Button) findViewById(R.id.cancel)).setOnClickListener(this);
}
/**
* On checkbox changed
*/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
{
switch (buttonView.getId()) {
case R.id.nickserv_checkbox:
nickservPasswordLabel.setEnabled(isChecked);
nickservPasswordEditText.setEnabled(isChecked);
if (!isChecked) {
nickservPasswordEditText.setText("");
}
break;
case R.id.sasl_checkbox:
saslUsernameLabel.setEnabled(isChecked);
saslUsernameEditText.setEnabled(isChecked);
saslPasswordLabel.setEnabled(isChecked);
saslPasswordEditText.setEnabled(isChecked);
if (!isChecked) {
saslUsernameEditText.setText("");
saslPasswordEditText.setText("");
}
break;
}
}
/**
* On click on button
*/
@Override
public void onClick(View v)
{
switch (v.getId()) {
case R.id.ok:
Intent intent = new Intent();
intent.putExtra(Extra.NICKSERV_PASSWORD, nickservPasswordEditText.getText().toString());
intent.putExtra(Extra.SASL_USER, saslUsernameEditText.getText().toString());
intent.putExtra(Extra.SASL_PASSWORD, saslPasswordEditText.getText().toString());
setResult(RESULT_OK, intent);
finish();
break;
case R.id.cancel:
setResult(RESULT_CANCELED);
finish();
break;
}
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.activity;
import org.yaaic.R;
@ -38,27 +38,30 @@ import android.widget.EditText;
*/
public class JoinActivity extends Activity implements OnClickListener
{
/**
* On create
*/
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.join);
((Button) findViewById(R.id.join)).setOnClickListener(this);
((EditText) findViewById(R.id.channel)).setSelection(1);
}
/**
* On click
*/
public void onClick(View v)
{
Intent intent = new Intent();
intent.putExtra("channel", ((EditText) findViewById(R.id.channel)).getText().toString());
setResult(RESULT_OK, intent);
finish();
}
@Override
public void onClick(View v)
{
Intent intent = new Intent();
intent.putExtra("channel", ((EditText) findViewById(R.id.channel)).getText().toString());
setResult(RESULT_OK, intent);
finish();
}
}

View File

@ -0,0 +1,212 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2015 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.TypedValue;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.yaaic.R;
import org.yaaic.Yaaic;
import org.yaaic.fragment.ConversationFragment;
import org.yaaic.fragment.OverviewFragment;
import org.yaaic.fragment.SettingsFragment;
import org.yaaic.irc.IRCBinder;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Extra;
import org.yaaic.model.Server;
import org.yaaic.model.Status;
/**
* The main activity of Yaaic. We'll add, remove and replace fragments here.
*/
public class MainActivity extends AppCompatActivity implements YaaicActivity, ServiceConnection {
private ActionBarDrawerToggle toggle;
private Toolbar toolbar;
private DrawerLayout drawer;
private IRCBinder binder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeToolbar();
initializeDrawer();
if (savedInstanceState == null) {
onOverview(null);
}
}
public void initializeToolbar() {
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
public void initializeDrawer() {
drawer = (DrawerLayout) findViewById(R.id.drawer);
toggle = new ActionBarDrawerToggle(this, drawer, toolbar, 0, 0);
drawer.setDrawerListener(toggle);
LinearLayout serverContainer = (LinearLayout) findViewById(R.id.server_container);
for (final Server server : Yaaic.getInstance().getServersAsArrayList()) {
TextView serverView = (TextView) getLayoutInflater().inflate(R.layout.item_drawer_server, drawer, false);
serverView.setText(server.getTitle());
serverView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onServerSelected(server);
drawer.closeDrawers();
}
});
serverContainer.addView(serverView, 0);
}
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
toggle.syncState();
}
@Override
protected void onResume() {
super.onResume();
Intent intent = new Intent(this, IRCService.class);
intent.setAction(IRCService.ACTION_BACKGROUND);
startService(intent);
bindService(intent, this, 0);
}
@Override
protected void onPause() {
super.onPause();
if (binder != null && binder.getService() != null) {
binder.getService().checkServiceStatus();
}
unbindService(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (toggle.onOptionsItemSelected(item)) {
return true;
}
return false;
}
@Override
public void onServerSelected(Server server) {
Bundle arguments = new Bundle();
if (server.getStatus() == Status.DISCONNECTED && !server.mayReconnect()) {
server.setStatus(Status.PRE_CONNECTING);
arguments.putBoolean(Extra.CONNECT, true);
}
arguments.putInt(Extra.SERVER_ID, server.getId());
ConversationFragment fragment = new ConversationFragment();
fragment.setArguments(arguments);
switchToFragment(fragment, ConversationFragment.TRANSACTION_TAG);
}
public void onOverview(View view) {
switchToFragment(new OverviewFragment(), OverviewFragment.TRANSACTION_TAG);
}
public void onSettings(View view) {
switchToFragment(new SettingsFragment(), SettingsFragment.TRANSACTION_TAG);
}
private void switchToFragment(Fragment fragment, String tag) {
drawer.closeDrawers();
getFragmentManager()
.beginTransaction()
.setCustomAnimations(
R.animator.card_flip_right_in, R.animator.card_flip_right_out,
R.animator.card_flip_left_in, R.animator.card_flip_left_out)
.replace(R.id.container, fragment, tag)
.commit();
}
public void onAbout(View view) {
drawer.closeDrawers();
startActivity(new Intent(this, AboutActivity.class));
}
@Override
public IRCBinder getBinder() {
return binder;
}
@Override
public Toolbar getToolbar() {
return toolbar;
}
@Override
public void setToolbarTitle(String title) {
toolbar.setTitle(title);
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder = (IRCBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
binder = null;
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.activity;
import org.yaaic.R;
@ -35,19 +35,19 @@ import android.widget.TextView;
*/
public class MessageActivity extends Activity
{
/**
* On create
*/
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.message);
((TextView) findViewById(R.id.message)).setText(
getIntent().getExtras().getString(Extra.MESSAGE)
);
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.message);
((TextView) findViewById(R.id.message)).setText(
getIntent().getExtras().getString(Extra.MESSAGE)
);
}
}

View File

@ -0,0 +1,72 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import org.yaaic.R;
import org.yaaic.adapter.UserActionListAdapter;
import org.yaaic.model.Extra;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.ListView;
import android.widget.TextView;
/**
* UserActivity
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class UserActivity extends ListActivity
{
private String nickname;
/**
* On create
*/
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.user);
setListAdapter(new UserActionListAdapter());
nickname = getIntent().getStringExtra(Extra.USER);
((TextView) findViewById(R.id.nickname)).setText(nickname);
}
/**
* On action selected
*/
@Override
protected void onListItemClick(ListView list, View view, int position, long id)
{
Intent intent = new Intent();
intent.putExtra(Extra.ACTION, (int) id);
intent.putExtra(Extra.USER, nickname);
setResult(RESULT_OK, intent);
finish();
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,9 +17,11 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.activity;
import java.util.Arrays;
import org.yaaic.R;
import org.yaaic.model.Extra;
@ -29,8 +31,8 @@ import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
/**
* User Activity - Shows a list of users in the current channel
@ -39,30 +41,35 @@ import android.widget.AdapterView.OnItemClickListener;
*/
public class UsersActivity extends ListActivity implements OnItemClickListener
{
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.users);
String[] users = getIntent().getExtras().getStringArray(Extra.USERS);
getListView().setAdapter(new ArrayAdapter<String>(this, R.layout.useritem, users));
getListView().setOnItemClickListener(this);
}
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
/**
* On user selected
*/
public void onItemClick(AdapterView<?> list, View item, int position, long id)
{
Intent intent = new Intent();
intent.putExtra(Extra.USER, (String) getListView().getAdapter().getItem(position));
setResult(RESULT_OK, intent);
finish();
}
setContentView(R.layout.users);
final String[] users = getIntent().getExtras().getStringArray(Extra.USERS);
getListView().setOnItemClickListener(this);
// Add sorted list of users in own thread to avoid blocking UI
// TODO: Move to a background task and show loading indicator while sorting
Arrays.sort(users, String.CASE_INSENSITIVE_ORDER);
getListView().setAdapter(new ArrayAdapter<String>(UsersActivity.this, R.layout.useritem, users));
}
/**
* On user selected
*/
@Override
public void onItemClick(AdapterView<?> list, View item, int position, long id)
{
Intent intent = new Intent();
intent.putExtra(Extra.USER, (String) getListView().getAdapter().getItem(position));
setResult(RESULT_OK, intent);
finish();
}
}

View File

@ -0,0 +1,39 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2015 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import android.support.v7.widget.Toolbar;
import org.yaaic.irc.IRCBinder;
import org.yaaic.model.Server;
/**
* Interface for fragments accessing functionality of the main activity.
*/
public interface YaaicActivity {
IRCBinder getBinder();
Toolbar getToolbar();
void setToolbarTitle(String title);
void onServerSelected(Server server);
}

View File

@ -0,0 +1,277 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.adapter;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import org.yaaic.listener.MessageClickListener;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import org.yaaic.view.MessageListView;
import java.util.HashMap;
import java.util.LinkedList;
/**
* Adapter for displaying a pager of conversations.
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class ConversationPagerAdapter extends PagerAdapter
{
private final Server server;
private LinkedList<ConversationInfo> conversations;
private final HashMap<Integer, View> views;
/**
* Container class to remember conversation and view association.
*/
public class ConversationInfo {
public Conversation conv;
public MessageListAdapter adapter;
public MessageListView view;
public ConversationInfo(Conversation conv) {
this.conv = conv;
this.adapter = null;
this.view = null;
}
}
/**
* Create a new {@link ConversationPagerAdapter} instance.
*/
public ConversationPagerAdapter(Context context, Server server) {
this.server = server;
conversations = new LinkedList<ConversationInfo>();
views = new HashMap<Integer, View>();
}
/**
* Add a conversation to the adapter.
*
* @param conversation
*/
public void addConversation(Conversation conversation) {
conversations.add(new ConversationInfo(conversation));
notifyDataSetChanged();
}
/**
* Remove the conversation at the given position from the adapter.
*
* @param position
*/
public void removeConversation(int position) {
conversations.remove(position);
notifyDataSetChanged();
}
/**
* Get position of given item.
*/
@Override
public int getItemPosition(Object object)
{
if (views.containsKey(object)) {
return POSITION_UNCHANGED;
}
return POSITION_NONE;
}
/**
* Get item at position
*/
public Conversation getItem(int position)
{
ConversationInfo convInfo = getItemInfo(position);
if (convInfo != null) {
return convInfo.conv;
} else {
return null;
}
}
/**
* Get the adapter of the {@link MessageListView} at the given position.
*
* @param position
* @return
*/
public MessageListAdapter getItemAdapter(int position)
{
ConversationInfo convInfo = getItemInfo(position);
if (convInfo != null) {
return convInfo.adapter;
} else {
return null;
}
}
/**
* Get the adapter of the {@link MessageListView} for the conversation
* with the given name.
*
* @param name
* @return
*/
public MessageListAdapter getItemAdapter(String name)
{
return getItemAdapter(getPositionByName(name));
}
/**
* Get ConversationInfo on item at position
*
* @param position
*/
private ConversationInfo getItemInfo(int position) {
if (position >= 0 && position < conversations.size()) {
return conversations.get(position);
}
return null;
}
/**
* Get an item by the channel's name
*
* @return The item
*/
public int getPositionByName(String name)
{
// Optimization - cache field lookups
int mSize = conversations.size();
LinkedList<ConversationInfo> mItems = this.conversations;
for (int i = 0; i < mSize; i++) {
if (mItems.get(i).conv.getName().equalsIgnoreCase(name)) {
return i;
}
}
return -1;
}
/**
* Remove all conversations.
*/
public void clearConversations()
{
conversations = new LinkedList<ConversationInfo>();
}
/**
* Get number of conversations from this adapter.
*/
@Override
public int getCount()
{
return conversations.size();
}
/**
* Determines whether a page View is associated with a specific key object.
*/
@Override
public boolean isViewFromObject(View view, Object object)
{
return view == object;
}
/**
* Create a view object for the conversation at the given position.
*/
@Override
public Object instantiateItem(View collection, int position) {
// ConversationInfo convInfo = getItemInfo(position);
ConversationInfo convInfo = conversations.get(position);
View view;
if (convInfo.view != null) {
view = convInfo.view;
} else {
view = renderConversation(convInfo, collection);
}
views.put(position, view);
((ViewPager) collection).addView(view);
return view;
}
/**
* Render the given conversation and return the new view.
*
* @param convInfo
* @param parent
* @return
*/
private MessageListView renderConversation(ConversationInfo convInfo, View parent)
{
MessageListView list = new MessageListView(parent.getContext());
convInfo.view = list;
list.setOnItemClickListener(MessageClickListener.getInstance());
MessageListAdapter adapter = convInfo.adapter;
if (adapter == null) {
adapter = new MessageListAdapter(convInfo.conv, parent.getContext());
convInfo.adapter = adapter;
}
list.setAdapter(adapter);
list.setSelection(adapter.getCount() - 1); // scroll to bottom
return list;
}
/**
* Remove the given view from the adapter and collection.
*/
@Override
public void destroyItem(View collection, int position, Object view) {
((ViewPager) collection).removeView((View) view);
views.remove(position);
}
/**
* Get the title for the given position.
*/
@Override
public String getPageTitle(int position)
{
Conversation conversation = getItem(position);
if (conversation.getType() == Conversation.TYPE_SERVER) {
return server.getTitle();
} else {
return conversation.getName();
}
}
}

View File

@ -0,0 +1,177 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.adapter;
import java.util.LinkedList;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import android.content.Context;
import android.database.DataSetObserver;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
/**
* Adapter for (channel) messages in a ListView
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class MessageListAdapter extends BaseAdapter
{
private final LinkedList<TextView> messages;
private final Context context;
private int historySize;
/**
* Create a new MessageAdapter
*
* @param channel
* @param context
*/
public MessageListAdapter(Conversation conversation, Context context)
{
LinkedList<TextView> messages = new LinkedList<TextView>();
// Render channel name as first message in channel
if (conversation.getType() != Conversation.TYPE_SERVER) {
Message header = new Message(conversation.getName());
header.setColor(Message.COLOR_RED);
messages.add(header.renderTextView(context));
}
// Optimization - cache field lookups
LinkedList<Message> mHistory = conversation.getHistory();
int mSize = mHistory.size();
for (int i = 0; i < mSize; i++) {
messages.add(mHistory.get(i).renderTextView(context));
}
// XXX: We don't want to clear the buffer, we want to add only
// buffered messages that are not already added (history)
conversation.clearBuffer();
this.messages = messages;
this.context = context;
historySize = conversation.getHistorySize();
}
/**
* Add a message to the list
*
* @param message
*/
public void addMessage(Message message)
{
messages.add(message.renderTextView(context));
if (messages.size() > historySize) {
messages.remove(0);
}
notifyDataSetChanged();
}
/**
* Add a list of messages to the list
*
* @param messages
*/
public void addBulkMessages(LinkedList<Message> messages)
{
LinkedList<TextView> mMessages = this.messages;
Context mContext = this.context;
int mSize = messages.size();
for (int i = mSize - 1; i > -1; i--) {
mMessages.add(messages.get(i).renderTextView(mContext));
if (mMessages.size() > historySize) {
mMessages.remove(0);
}
}
notifyDataSetChanged();
}
/**
* Get number of items
*
* @return
*/
@Override
public int getCount()
{
return messages.size();
}
/**
* Get item at given position
*
* @param position
* @return
*/
@Override
public TextView getItem(int position)
{
return messages.get(position);
}
/**
* Get id of item at given position
*
* @param position
* @return
*/
@Override
public long getItemId(int position)
{
return position;
}
/**
* Get item view for the given position
*
* @param position
* @param convertView
* @param parent
* @return
*/
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
return getItem(position);
}
/**
* XXX This is almost certainly covering up a bug elsewhere -- find it!
*/
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
if (observer == null) {
return;
}
super.unregisterDataSetObserver(observer);
}
}

View File

@ -0,0 +1,133 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.yaaic.R;
import org.yaaic.Yaaic;
import org.yaaic.menu.ServerPopupMenu;
import org.yaaic.model.Server;
import java.util.List;
/**
* RecyclerView adapter for server cards.
*/
public class ServersAdapter extends RecyclerView.Adapter<ServersAdapter.ViewHolder> {
public interface ClickListener {
void onServerSelected(Server server);
void onConnectToServer(Server server);
void onDisconnectFromServer(Server server);
void onEditServer(Server server);
void onDeleteServer(Server server);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public final TextView titleView;
public final TextView hostView;
public final ImageView connectionView;
public final View menuView;
public final ServerPopupMenu popupMenu;
public ViewHolder(View view, ClickListener listener) {
super(view);
titleView = (TextView) view.findViewById(R.id.title);
hostView = (TextView) view.findViewById(R.id.host);
connectionView = (ImageView) view.findViewById(R.id.connection);
menuView = view.findViewById(R.id.menu);
popupMenu = new ServerPopupMenu(
view.getContext(), view.findViewById(R.id.menu),
listener
);
}
}
private List<Server> servers;
private ClickListener listener;
public ServersAdapter(ClickListener listener) {
this.listener = listener;
loadServers();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.
from(parent.getContext()).
inflate(R.layout.item_server, parent, false);
return new ViewHolder(view, listener);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final Server server = servers.get(position);
int colorResource = server.isConnected() ? R.color.connected : R.color.disconnected;
int color = holder.itemView.getContext().getResources().getColor(colorResource);
holder.titleView.setText(server.getTitle());
holder.titleView.setTextColor(color);
holder.connectionView.setImageResource(
server.isConnected()
? R.drawable.ic_navigation_server_connected
: R.drawable.ic_navigation_server_disconnected
);
holder.hostView.setText(String.format("%s @ %s : %d",
server.getIdentity().getNickname(),
server.getHost(),
server.getPort()
));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onServerSelected(server);
}
});
holder.popupMenu.updateServer(server);
}
/**
* Load servers from database
*
* Delegate call to yaaic instance
*/
public void loadServers() {
servers = Yaaic.getInstance().getServersAsArrayList();
notifyDataSetChanged();
}
@Override
public int getItemCount() {
return servers.size();
}
}

View File

@ -0,0 +1,129 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.adapter;
import org.yaaic.R;
import org.yaaic.model.User;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Adapter for user action lists
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class UserActionListAdapter extends BaseAdapter
{
/**
* Action IDs
*/
private final int[] actions = {
User.ACTION_REPLY,
User.ACTION_QUERY,
User.ACTION_OP,
User.ACTION_DEOP,
User.ACTION_VOICE,
User.ACTION_DEVOICE,
User.ACTION_KICK,
User.ACTION_BAN
};
/**
* Labels for actions
*/
private final int[] labels = {
R.string.user_action_reply,
R.string.user_action_query,
R.string.user_action_op,
R.string.user_action_deop,
R.string.user_action_voice,
R.string.user_action_devoice,
R.string.user_action_kick,
R.string.user_action_ban
};
/**
* Icons for actions
*/
private final int[] icons = {
R.drawable.action_reply,
R.drawable.action_query,
R.drawable.action_op,
R.drawable.action_deop,
R.drawable.action_voice,
R.drawable.action_devoice,
R.drawable.action_kick,
R.drawable.action_ban,
};
/**
* Get number of actions
*/
@Override
public int getCount()
{
return actions.length;
}
/**
* Get object for given position
*/
@Override
public Object getItem(int position)
{
return null;
}
/**
* Get item id for given position
*/
@Override
public long getItemId(int position)
{
return actions[position];
}
/**
* Get view for given position
*/
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.actionitem, null);
}
TextView textView = (TextView) convertView.findViewById(R.id.label);
ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
textView.setText(labels[position]);
iconView.setImageResource(icons[position]);
return convertView;
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2012 Sebastian Kaspari
*
* 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 org.yaaic.adapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
/**
* Implementation of {@link PagerAdapter} that represents each page as a {@link View}.
*
* @author Sebastian Kaspari <s.kaspari@gmail.com>
*/
public abstract class ViewPagerAdapter extends PagerAdapter
{
/**
* Get a View that displays the data at the specified position in the data set.
*
* @param position The position of the item within the adapter's data set of the item whose view we want.
* @param pager The ViewPager that this view will eventually be attached to.
*
* @return A View corresponding to the data at the specified position.
*/
public abstract View getView(int position, ViewPager pager);
/**
* Determines whether a page View is associated with a specific key object as
* returned by instantiateItem(ViewGroup, int).
*
* @param view Page View to check for association with object
* @param object Object to check for association with view
*
* @return true if view is associated with the key object object.
*/
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
/**
* Create the page for the given position.
*
* @param container The containing View in which the page will be shown.
* @param position The page position to be instantiated.
*
* @return Returns an Object representing the new page. This does not need
* to be a View, but can be some other container of the page.
*/
@Override
public Object instantiateItem(ViewGroup container, int position) {
ViewPager pager = (ViewPager) container;
View view = getView(position, pager);
pager.addView(view);
return view;
}
/**
* Remove a page for the given position.
*
* @param container The containing View from which the page will be removed.
* @param position The page position to be removed.
* @param view The same object that was returned by instantiateItem(View, int).
*/
@Override
public void destroyItem(ViewGroup container, int position, Object view) {
((ViewPager) container).removeView((View) view);
}
}

View File

@ -0,0 +1,90 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Base class for commands
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public abstract class BaseHandler
{
/**
* Execute the command
*
* @param params The params given (0 is the command itself)
* @param server The server object
* @param channel The channel object or null if no channel is selected
* @param service The service with all server connections
* @throws CommandException if command couldn't be executed
*/
public abstract void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException;
/**
* Get the usage description for this command
*
* @return The usage description
*/
public abstract String getUsage();
/**
* Get the description for this command
*
* @param context The current context. Needed for getting string resources
* @return
*/
public abstract String getDescription(Context context);
/**
* Merge params to a string
*
* @params params The params to merge
*/
public static String mergeParams(String[] params)
{
return mergeParams(params, 1);
}
/**
* Merge params to a string
*
* @param params The params to merge
* @param position Start at given param
*/
public static String mergeParams(String[] params, int position)
{
StringBuffer buffer = new StringBuffer();
for (; position < params.length; position++) {
buffer.append(params[position]);
buffer.append(" ");
}
return buffer.toString().trim();
}
}

View File

@ -0,0 +1,240 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command;
import java.util.HashMap;
import org.yaaic.command.handler.AMsgHandler;
import org.yaaic.command.handler.AwayHandler;
import org.yaaic.command.handler.BackHandler;
import org.yaaic.command.handler.CloseHandler;
import org.yaaic.command.handler.DCCHandler;
import org.yaaic.command.handler.DeopHandler;
import org.yaaic.command.handler.DevoiceHandler;
import org.yaaic.command.handler.EchoHandler;
import org.yaaic.command.handler.HelpHandler;
import org.yaaic.command.handler.JoinHandler;
import org.yaaic.command.handler.KickHandler;
import org.yaaic.command.handler.MeHandler;
import org.yaaic.command.handler.ModeHandler;
import org.yaaic.command.handler.MsgHandler;
import org.yaaic.command.handler.NamesHandler;
import org.yaaic.command.handler.NickHandler;
import org.yaaic.command.handler.NoticeHandler;
import org.yaaic.command.handler.OpHandler;
import org.yaaic.command.handler.PartHandler;
import org.yaaic.command.handler.QueryHandler;
import org.yaaic.command.handler.QuitHandler;
import org.yaaic.command.handler.RawHandler;
import org.yaaic.command.handler.TopicHandler;
import org.yaaic.command.handler.VoiceHandler;
import org.yaaic.command.handler.WhoisHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Intent;
/**
* Parser for commands
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class CommandParser
{
private final HashMap<String, BaseHandler> commands;
private final HashMap<String, String> aliases;
private static CommandParser instance;
/**
* Create a new CommandParser instance
*/
private CommandParser()
{
commands = new HashMap<String, BaseHandler>();
// Commands
commands.put("nick", new NickHandler());
commands.put("join", new JoinHandler());
commands.put("me", new MeHandler());
commands.put("names", new NamesHandler());
commands.put("echo", new EchoHandler());
commands.put("topic", new TopicHandler());
commands.put("quit", new QuitHandler());
commands.put("op", new OpHandler());
commands.put("voice", new VoiceHandler());
commands.put("deop", new DeopHandler());
commands.put("devoice", new DevoiceHandler());
commands.put("kick", new KickHandler());
commands.put("query", new QueryHandler());
commands.put("part", new PartHandler());
commands.put("close", new CloseHandler());
commands.put("notice", new NoticeHandler());
commands.put("dcc", new DCCHandler());
commands.put("mode", new ModeHandler());
commands.put("help", new HelpHandler());
commands.put("away", new AwayHandler());
commands.put("back", new BackHandler());
commands.put("whois", new WhoisHandler());
commands.put("msg", new MsgHandler());
commands.put("quote", new RawHandler());
commands.put("amsg", new AMsgHandler());
aliases = new HashMap<String, String>();
// Aliases
aliases.put("j","join");
aliases.put("q", "query");
aliases.put("h", "help");
aliases.put("raw", "quote");
aliases.put("w", "whois");
}
/**
* Get the global CommandParser instance
*
* @return
*/
public static synchronized CommandParser getInstance()
{
if (instance == null) {
instance = new CommandParser();
}
return instance;
}
/**
* Get the commands HashMap
*
* @return HashMap - command, commandHandler
*/
public HashMap<String, BaseHandler> getCommands()
{
return commands;
}
/**
* Get the command aliases HashMap
*
* @return HashMap - alias, command the alias belogs to
*/
public HashMap<String, String> getAliases()
{
return aliases;
}
/**
* Is the given command a valid client command?
*
* @param command The (client) command to check (/command)
* @return true if the command can be handled by the client, false otherwise
*/
public boolean isClientCommand(String command)
{
return commands.containsKey(command.toLowerCase()) || aliases.containsKey(command.toLowerCase());
}
/**
* Handle a client command
*
* @param type Type of the command (/type param1 param2 ..)
* @param params The parameters of the command (0 is the command itself)
* @param server The current server
* @param conversation The selected conversation
* @param service The service handling the connections
*/
public void handleClientCommand(String type, String[] params, Server server, Conversation conversation, IRCService service)
{
BaseHandler command = null;
if (commands.containsKey(type.toLowerCase())) {
command = commands.get(type.toLowerCase());
} else if (aliases.containsKey(type.toLowerCase())) {
String commandInCommands = aliases.get(type.toLowerCase());
command = commands.get(commandInCommands);
}
try {
command.execute(params, server, conversation, service);
} catch(CommandException e) {
// Command could not be executed
if (conversation != null) {
Message errorMessage = new Message(type + ": " + e.getMessage());
errorMessage.setColor(Message.COLOR_RED);
conversation.addMessage(errorMessage);
// XXX:I18N - How to get a context here? (command_syntax)
Message usageMessage = new Message("Syntax: " + command.getUsage());
conversation.addMessage(usageMessage);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
}
}
}
/**
* Handle a server command
*
* @param type Type of the command (/type param1 param2 ..)
* @param params The parameters of the command (0 is the command itself)
* @param server The current server
* @param conversation The selected conversation
* @param service The service handling the connections
*/
public void handleServerCommand(String type, String[] params, Server server, Conversation conversation, IRCService service)
{
if (params.length > 1) {
service.getConnection(server.getId()).sendRawLineViaQueue(
type.toUpperCase() + " " + BaseHandler.mergeParams(params)
);
} else {
service.getConnection(server.getId()).sendRawLineViaQueue(type.toUpperCase());
}
}
/**
* Parse the given line
*
* @param line
*/
public void parse(String line, Server server, Conversation conversation, IRCService service)
{
line = line.trim().substring(1); // cut the slash
String[] params = line.split(" ");
String type = params[0];
if (isClientCommand(type)) {
handleClientCommand(type, params, server, conversation, service);
} else {
handleServerCommand(type, params, server, conversation, service);
}
}
}

View File

@ -0,0 +1,95 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import java.util.Collection;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
* Command: /amsg <message>
*
* Send a message to all channels on the server
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class AMsgHandler extends BaseHandler
{
/**
* Execute /amsg
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 1) {
String text = BaseHandler.mergeParams(params);
Collection<Conversation> mConversations = server.getConversations();
for (Conversation currentConversation : mConversations) {
if (currentConversation.getType() == Conversation.TYPE_CHANNEL) {
Message message = new Message("<" + service.getConnection(server.getId()).getNick() + "> " + text);
currentConversation.addMessage(message);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
currentConversation.getName()
);
service.sendBroadcast(intent);
service.getConnection(server.getId()).sendMessage(currentConversation.getName(), text);
}
}
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /amsg
*/
@Override
public String getUsage()
{
return "/amsg <message>";
}
/**
* Description of /amsg
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_amsg);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /away [<reason>]
*
@ -35,30 +38,30 @@ import org.yaaic.model.Server;
*/
public class AwayHandler extends BaseHandler
{
/**
* Execute /away
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
service.getConnection(server.getId()).sendRawLineViaQueue("AWAY " + BaseHandler.mergeParams(params));
}
/**
* Execute /away
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
service.getConnection(server.getId()).sendRawLineViaQueue("AWAY " + BaseHandler.mergeParams(params));
}
/**
* Get description of /away
*/
@Override
public String getDescription()
{
return "Sets you away";
}
/**
* Get description of /away
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_away);
}
/**
* Get usage of /away
*/
@Override
public String getUsage()
{
return "/away [<reason>]";
}
/**
* Get usage of /away
*/
@Override
public String getUsage()
{
return "/away [<reason>]";
}
}

View File

@ -0,0 +1,67 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /back
*
* Turn off the away status
*
* @author Francesco Lavra <francescola...@interfree.it>
*/
public class BackHandler extends BaseHandler
{
/**
* Execute /back
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
service.getConnection(server.getId()).sendRawLineViaQueue("AWAY");
}
/**
* Get description of /back
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_back);
}
/**
* Get usage of /back
*/
@Override
public String getUsage()
{
return "/back";
}
}

View File

@ -0,0 +1,87 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
* Command: /close
*
* Closes the current window
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class CloseHandler extends BaseHandler
{
/**
* Execute /close
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() == Conversation.TYPE_SERVER) {
throw new CommandException(service.getString(R.string.close_server_window));
}
if (params.length == 1) {
if (conversation.getType() == Conversation.TYPE_CHANNEL) {
service.getConnection(server.getId()).partChannel(conversation.getName());
}
if (conversation.getType() == Conversation.TYPE_QUERY) {
server.removeConversation(conversation.getName());
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_REMOVE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
}
}
}
/**
* Usage of /close
*/
@Override
public String getUsage()
{
return "/close";
}
/**
* Description of /close
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_close);
}
}

View File

@ -0,0 +1,91 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import java.io.File;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /dcc SEND <nickname> <file>
*
* Send a file to a user
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class DCCHandler extends BaseHandler
{
/**
* Execute /dcc
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 4) {
if (!params[1].equalsIgnoreCase("SEND")) {
throw new CommandException(service.getString(R.string.dcc_only_send));
}
File file = new File(params[3]);
if (!file.exists()) {
throw new CommandException(service.getString(R.string.dcc_file_not_found, params[3]));
}
service.getConnection(server.getId()).dccSendFile(file, params[2], 60000);
Message message = new Message(service.getString(R.string.dcc_waiting_accept, params[2]));
message.setColor(Message.COLOR_GREY);
conversation.addMessage(message);
service.sendBroadcast(
Broadcast.createConversationIntent(Broadcast.CONVERSATION_MESSAGE, server.getId(), conversation.getName())
);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /dcc
*/
@Override
public String getUsage()
{
return "/dcc SEND <nickname> <file>";
}
/**
* Description of /dcc
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_dcc);
}
}

View File

@ -0,0 +1,73 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /deop <nickname>
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class DeopHandler extends BaseHandler
{
/**
* Execute /deop
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException(service.getString(R.string.only_usable_from_channel));
}
if (params.length == 2) {
service.getConnection(server.getId()).deOp(conversation.getName(), params[1]);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /deop
*/
@Override
public String getUsage()
{
return "/deop <nickname>";
}
/**
* Description of /deop
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_deop);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /devoice <nickname>
*
@ -33,38 +36,38 @@ import org.yaaic.model.Server;
*/
public class DevoiceHandler extends BaseHandler
{
/**
* Execute /devoice
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException("Only usable from within a channel");
}
if (params.length == 2) {
service.getConnection(server.getId()).deVoice(conversation.getName(), params[1]);
} else {
throw new CommandException("Invalid number of params");
}
}
/**
* Usage of /devoice
*/
@Override
public String getUsage()
{
return "/devoice <nickname>";
}
/**
* Execute /devoice
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException(service.getString(R.string.only_usable_from_channel));
}
/**
* Description of /devoice
*/
@Override
public String getDescription()
{
return "Remove voice status from a user";
}
if (params.length == 2) {
service.getConnection(server.getId()).deVoice(conversation.getName(), params[1]);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /devoice
*/
@Override
public String getUsage()
{
return "/devoice <nickname>";
}
/**
* Description of /devoice
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_devoice);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,9 +17,10 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
@ -28,6 +29,7 @@ import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
@ -37,42 +39,42 @@ import android.content.Intent;
*/
public class EchoHandler extends BaseHandler
{
/**
* Execute /echo
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 1) {
Message message = new Message(BaseHandler.mergeParams(params));
conversation.addMessage(message);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
} else {
throw new CommandException("Text is missing");
}
}
/**
* Usage of /echo
*/
@Override
public String getUsage()
{
return "/echo <text>";
}
/**
* Execute /echo
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 1) {
Message message = new Message(BaseHandler.mergeParams(params));
conversation.addMessage(message);
/**
* Description of /echo
*/
@Override
public String getDescription()
{
return "Print text to window";
}
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
} else {
throw new CommandException(service.getString(R.string.text_missing));
}
}
/**
* Usage of /echo
*/
@Override
public String getUsage()
{
return "/echo <text>";
}
/**
* Description of /echo
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_echo);
}
}

View File

@ -0,0 +1,155 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import java.util.HashMap;
import java.util.Set;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.command.CommandParser;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
* Command: /help
*
* @author Karol Gliniecki <karol.gliniecki@googlemail.com>
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class HelpHandler extends BaseHandler
{
/**
* Execute /help
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 2) {
showCommandDetails(service, server, conversation, params[1]);
} else if (params.length == 1) {
showAllCommands(service, server, conversation);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Show all available commands
*
* @param conversation
* @param server
* @param service
*/
private void showAllCommands(IRCService service, Server server, Conversation conversation)
{
CommandParser cp = CommandParser.getInstance();
StringBuffer commandList = new StringBuffer(service.getString(R.string.available_commands));
commandList.append("\n");
HashMap<String, BaseHandler> commands = cp.getCommands();
HashMap<String, String> aliases = cp.getAliases();
Set<String> commandKeys = commands.keySet();
Set<String> aliasesKeys = aliases.keySet();
for (Object command : commandKeys) {
String alias = "";
for (Object aliasCommand : aliasesKeys) {
if (command.equals(aliases.get(aliasCommand))) {
alias = " " + service.getString(R.string.logical_or) + " /" + aliasCommand;
break;
}
}
commandList.append("/" + command.toString() + alias + " - "+commands.get(command).getDescription(service) + "\n");
}
Message message = new Message(commandList.toString());
message.setColor(Message.COLOR_YELLOW);
conversation.addMessage(message);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
}
/**
* Show details of a single command
*
* @param conversation
* @param server
* @param service
* @param command
* @throws CommandException
*/
private void showCommandDetails(IRCService service, Server server, Conversation conversation, String command) throws CommandException
{
CommandParser cp = CommandParser.getInstance();
HashMap<String, BaseHandler> commands = cp.getCommands();
if (commands.containsKey(command)) {
// XXX:I18N - String building salad :)
Message message = new Message("Help of /" + command + "\n" + commands.get(command).getUsage() + "\n" + commands.get(command).getDescription(service) + "\n");
message.setColor(Message.COLOR_YELLOW);
conversation.addMessage(message);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
} else {
throw new CommandException(service.getString(R.string.unknown_command, command));
}
}
/**
* Usage of /help
*/
@Override
public String getUsage()
{
return "/help [<command>]";
}
/**
* Description of /help
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_help);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /join <channel> [<key>]
*
@ -33,36 +36,36 @@ import org.yaaic.model.Server;
*/
public class JoinHandler extends BaseHandler
{
/**
* Execute /join
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 2) {
service.getConnection(server.getId()).joinChannel(params[1]);
} else if (params.length == 3) {
service.getConnection(server.getId()).joinChannel(params[1], params[2]);
} else {
throw new CommandException("Invalid number of params");
}
}
/**
* Usage of /join
*/
@Override
public String getUsage()
{
return "/join <channel> [<key>]";
}
/**
* Execute /join
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 2) {
service.getConnection(server.getId()).joinChannel(params[1]);
} else if (params.length == 3) {
service.getConnection(server.getId()).joinChannel(params[1], params[2]);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Description of /join
*/
@Override
public String getDescription()
{
return "Join a channel";
}
/**
* Usage of /join
*/
@Override
public String getUsage()
{
return "/join <channel> [<key>]";
}
/**
* Description of /join
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_join);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /kick <nickname>
*
@ -35,38 +38,38 @@ import org.yaaic.model.Server;
*/
public class KickHandler extends BaseHandler
{
/**
* Execute /kick
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException("Only usable from within a channel");
}
if (params.length == 2) {
service.getConnection(server.getId()).kick(conversation.getName(), params[1]);
} else {
throw new CommandException("Invalid number of params");
}
}
/**
* Usage of /kick
*/
@Override
public String getUsage()
{
return "/kick <nickname>";
}
/**
* Execute /kick
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException(service.getString(R.string.only_usable_from_channel));
}
/**
* Description of /kick
*/
@Override
public String getDescription()
{
return "Kicks a user";
}
if (params.length == 2) {
service.getConnection(server.getId()).kick(conversation.getName(), params[1]);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /kick
*/
@Override
public String getUsage()
{
return "/kick <nickname>";
}
/**
* Description of /kick
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_kick);
}
}

View File

@ -0,0 +1,90 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
* Command: /me <action>
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class MeHandler extends BaseHandler
{
/**
* Execute /me
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() == Conversation.TYPE_SERVER) {
throw new CommandException(service.getString(R.string.only_usable_from_channel_or_query));
}
if (params.length > 1) {
String action = BaseHandler.mergeParams(params);
String nickname = service.getConnection(server.getId()).getNick();
Message message = new Message(nickname + " " + action);
message.setIcon(R.drawable.action);
server.getConversation(conversation.getName()).addMessage(message);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
service.getConnection(server.getId()).sendAction(conversation.getName(), action);
} else {
throw new CommandException(service.getString(R.string.text_missing));
}
}
/**
* Usage of /me
*/
@Override
public String getUsage()
{
return "/me <text>";
}
/**
* Description of /me
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_me);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /mode <channel> <mode>
*
@ -35,36 +38,36 @@ import org.yaaic.model.Server;
*/
public class ModeHandler extends BaseHandler
{
/**
* Execute /mode
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 2) {
String modes = BaseHandler.mergeParams(params, 2);
service.getConnection(server.getId()).setMode(params[1], modes);
} else {
throw new CommandException("Invalid number of params");
}
}
/**
* Usage of /mode
*/
@Override
public String getUsage()
{
return "/mode <channel> <mode>";
}
/**
* Execute /mode
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 2) {
String modes = BaseHandler.mergeParams(params, 2);
/**
* Description of /mode
*/
@Override
public String getDescription()
{
return "Change channel modes";
}
service.getConnection(server.getId()).setMode(params[1], modes);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /mode
*/
@Override
public String getUsage()
{
return "/mode <channel> <mode>";
}
/**
* Description of /mode
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_mode);
}
}

View File

@ -0,0 +1,90 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
* Command: /msg <target> <message>
*
* Send a message to a channel or user
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class MsgHandler extends BaseHandler
{
/**
* Execute /msg
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 2) {
String text = BaseHandler.mergeParams(params, 2);
service.getConnection(server.getId()).sendMessage(params[1], text);
Conversation targetConversation = server.getConversation(params[1]);
if (targetConversation != null) {
Message message = new Message("<" + service.getConnection(server.getId()).getNick() + "> " + text);
targetConversation.addMessage(message);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
targetConversation.getName()
);
service.sendBroadcast(intent);
}
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /msg
*/
@Override
public String getUsage()
{
return "/msg <target> <message>";
}
/**
* Description of /msg
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_msg);
}
}

View File

@ -0,0 +1,93 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.jibble.pircbot.User;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
* Command: /names
* Lists all users currently in the selected channel
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class NamesHandler extends BaseHandler
{
/**
* Execute /names
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException(service.getString(R.string.only_usable_from_channel));
}
StringBuffer userList = new StringBuffer(service.getString(R.string.message_users_on_chan, conversation.getName()));
User[] mUsers = service.getConnection(server.getId()).getUsers(conversation.getName());
int mSize = mUsers.length;
for (int i = 0; i < mSize; i++) {
userList.append(" ");
userList.append(mUsers[i].getPrefix());
userList.append(mUsers[i].getNick());
}
Message message = new Message(userList.toString());
message.setColor(Message.COLOR_YELLOW);
conversation.addMessage(message);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
}
/**
* Usage of /names
*/
@Override
public String getUsage()
{
return "/names";
}
/**
* Description of /names
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_names);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /nick <nickname>
*
@ -33,34 +36,34 @@ import org.yaaic.model.Server;
*/
public class NickHandler extends BaseHandler
{
/**
* Execute /nick
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 2) {
service.getConnection(server.getId()).changeNick(params[1]);
} else {
throw new CommandException("Invalid number of params");
}
}
/**
* Usage of /nick
*/
@Override
public String getUsage()
{
return "/nick <nickname>";
}
/**
* Description of /nick
*/
@Override
public String getDescription()
{
return "change own nickname";
}
/**
* Execute /nick
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 2) {
service.getConnection(server.getId()).changeNick(params[1]);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /nick
*/
@Override
public String getUsage()
{
return "/nick <nickname>";
}
/**
* Description of /nick
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_nick);
}
}

View File

@ -0,0 +1,87 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
* Command: /notice <nickname> <message>
*
* Send a notice to an other user
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class NoticeHandler extends BaseHandler
{
/**
* Execute /notice
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 2) {
String text = BaseHandler.mergeParams(params);
Message message = new Message(">" + params[1] + "< " + text);
message.setIcon(R.drawable.info);
conversation.addMessage(message);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
server.getId(),
conversation.getName()
);
service.sendBroadcast(intent);
service.getConnection(server.getId()).sendNotice(params[1], text);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /notice
*/
@Override
public String getUsage()
{
return "/notice <nickname> <message>";
}
/**
* Description of /notice
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_notice);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /deop <nickname>
*
@ -33,38 +36,38 @@ import org.yaaic.model.Server;
*/
public class OpHandler extends BaseHandler
{
/**
* Execute /deop
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException("Only usable from within a channel");
}
if (params.length == 2) {
service.getConnection(server.getId()).op(conversation.getName(), params[1]);
} else {
throw new CommandException("Invalid number of params");
}
}
/**
* Usage of /deop
*/
@Override
public String getUsage()
{
return "/op <nickname>";
}
/**
* Execute /deop
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException(service.getString(R.string.only_usable_from_channel));
}
/**
* Description of /deop
*/
@Override
public String getDescription()
{
return "Give a user operator status";
}
if (params.length == 2) {
service.getConnection(server.getId()).op(conversation.getName(), params[1]);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /deop
*/
@Override
public String getUsage()
{
return "/op <nickname>";
}
/**
* Description of /deop
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_op);
}
}

View File

@ -0,0 +1,77 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /part [<channel>]
*
* Leave the current or the given channel
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class PartHandler extends BaseHandler
{
/**
* Execute /part
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 1) {
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException(service.getString(R.string.only_usable_from_channel));
}
service.getConnection(server.getId()).partChannel(conversation.getName());
} else if (params.length == 2) {
service.getConnection(server.getId()).partChannel(params[1]);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /part
*/
@Override
public String getUsage()
{
return "/part [<channel>]";
}
/**
* Description of /part
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_part);
}
}

View File

@ -0,0 +1,94 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Query;
import org.yaaic.model.Server;
import android.content.Context;
import android.content.Intent;
/**
* Command: /query <nickname>
*
* Opens a private chat with the given user
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class QueryHandler extends BaseHandler
{
/**
* Execute /query
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 2) {
// Simple validation
if (params[1].startsWith("#")) {
throw new CommandException(service.getString(R.string.query_to_channel));
}
Conversation query = server.getConversation(params[1]);
if (query != null) {
throw new CommandException(service.getString(R.string.query_exists));
}
query = new Query(params[1]);
query.setHistorySize(service.getSettings().getHistorySize());
server.addConversation(query);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_NEW,
server.getId(),
query.getName()
);
service.sendBroadcast(intent);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /query
*/
@Override
public String getUsage()
{
return "/query <nickname>";
}
/**
* Description of /query
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_query);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /quit [<reason>]
*
@ -33,34 +36,34 @@ import org.yaaic.model.Server;
*/
public class QuitHandler extends BaseHandler
{
/**
* Execute /quit
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 1) {
service.getConnection(server.getId()).quitServer();
} else {
service.getConnection(server.getId()).quitServer(BaseHandler.mergeParams(params));
}
}
/**
* Usage of /quit
*/
@Override
public String getUsage()
{
return "/quit [<reason>]";
}
/**
* Execute /quit
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length == 1) {
service.getConnection(server.getId()).quitServer();
} else {
service.getConnection(server.getId()).quitServer(BaseHandler.mergeParams(params));
}
}
/**
* Description of /quit
*/
@Override
public String getDescription()
{
return "disconnect from server";
}
/**
* Usage of /quit
*/
@Override
public String getUsage()
{
return "/quit [<reason>]";
}
/**
* Description of /quit
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_quit);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /raw <line>
*
@ -35,35 +38,35 @@ import org.yaaic.model.Server;
*/
public class RawHandler extends BaseHandler
{
/**
* Execute /raw
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 1) {
String line = BaseHandler.mergeParams(params);
service.getConnection(server.getId()).sendRawLineViaQueue(line);
} else {
throw new CommandException("Line is missing");
}
}
/**
* Usage of /raw
*/
@Override
public String getUsage()
{
return "/raw <line>";
}
/**
* Execute /raw
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length > 1) {
String line = BaseHandler.mergeParams(params);
service.getConnection(server.getId()).sendRawLineViaQueue(line);
} else {
throw new CommandException(service.getString(R.string.line_missing));
}
}
/**
* Description of /raw
*/
@Override
public String getDescription()
{
return "Send a raw line to the server";
}
/**
* Usage of /raw
*/
@Override
public String getUsage()
{
return "/raw <line>";
}
/**
* Description of /raw
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_raw);
}
}

View File

@ -0,0 +1,80 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Channel;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /topic [<topic>]
*
* Show the current topic or change the topic if a new topic is provided
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class TopicHandler extends BaseHandler
{
/**
* Execute /topic
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException(service.getString(R.string.only_usable_from_channel));
}
Channel channel = (Channel) conversation;
if (params.length == 1) {
// Show topic
service.getConnection(server.getId()).onTopic(channel.getName(), channel.getTopic(), "", 0, false);
} else if (params.length > 1) {
// Change topic
service.getConnection(server.getId()).setTopic(channel.getName(), BaseHandler.mergeParams(params));
}
}
/**
* Usage of /topic
*/
@Override
public String getUsage()
{
return "/topic [<topic>]";
}
/**
* Description of /topic
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_topic);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /voice <nickname>
*
@ -33,38 +36,38 @@ import org.yaaic.model.Server;
*/
public class VoiceHandler extends BaseHandler
{
/**
* Execute /voice
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException("Only usable from within a channel");
}
if (params.length == 2) {
service.getConnection(server.getId()).voice(conversation.getName(), params[1]);
} else {
throw new CommandException("Invalid number of params");
}
}
/**
* Usage of /voice
*/
@Override
public String getUsage()
{
return "/voice <nickname>";
}
/**
* Execute /voice
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (conversation.getType() != Conversation.TYPE_CHANNEL) {
throw new CommandException(service.getString(R.string.only_usable_from_channel));
}
/**
* Description of /voice
*/
@Override
public String getDescription()
{
return "Give a user voice status";
}
if (params.length == 2) {
service.getConnection(server.getId()).voice(conversation.getName(), params[1]);
} else {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
}
/**
* Usage of /voice
*/
@Override
public String getUsage()
{
return "/voice <nickname>";
}
/**
* Description of /voice
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_voice);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,15 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.command.handler;
import org.yaaic.R;
import org.yaaic.command.BaseHandler;
import org.yaaic.exception.CommandException;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
import android.content.Context;
/**
* Command: /whois <nickname>
*
@ -35,34 +38,34 @@ import org.yaaic.model.Server;
*/
public class WhoisHandler extends BaseHandler
{
/**
* Execute /whois
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length != 2) {
throw new CommandException("Invalid number of params");
}
service.getConnection(server.getId()).sendRawLineViaQueue("WHOIS " + params[1]);
}
/**
* Execute /whois
*/
@Override
public void execute(String[] params, Server server, Conversation conversation, IRCService service) throws CommandException
{
if (params.length != 2) {
throw new CommandException(service.getString(R.string.invalid_number_of_params));
}
/**
* Get description of /whois
*/
@Override
public String getDescription()
{
return "Get information about a user";
}
service.getConnection(server.getId()).sendRawLineViaQueue("WHOIS " + params[1]);
}
/**
* Get usage of /whois
*/
@Override
public String getUsage()
{
return "/whois <nickname>";
}
/**
* Get description of /whois
*/
@Override
public String getDescription(Context context)
{
return context.getString(R.string.command_desc_whois);
}
/**
* Get usage of /whois
*/
@Override
public String getUsage()
{
return "/whois <nickname>";
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,32 +17,31 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
*/
package org.yaaic.db;
import org.yaaic.R;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.provider.BaseColumns;
/**
* About activity
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
* Constants for the aliases table
*
* @author Sebastian Kaspari <s.kaspari@googlemail.com>
*/
public class AboutActivity extends Activity
public class AliasConstants implements BaseColumns
{
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.about);
}
public static final String TABLE_NAME = "aliases";
// fields
public static final String ALIAS = "alias";
public static final String IDENTITY = "identity";
/**
* All fields of the table
*/
public static final String[] ALL = {
_ID,
ALIAS,
IDENTITY,
};
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.db;
import android.provider.BaseColumns;
@ -29,19 +29,19 @@ import android.provider.BaseColumns;
*/
public interface ChannelConstants extends BaseColumns
{
public static final String TABLE_NAME = "channels";
// fields
public static final String NAME = "name";
public static final String PASSWORD = "password";
public static final String SERVER = "server";
/**
* All fields of the table
*/
public static final String[] ALL = {
NAME,
PASSWORD,
SERVER
};
public static final String TABLE_NAME = "channels";
// fields
public static final String NAME = "name";
public static final String PASSWORD = "password";
public static final String SERVER = "server";
/**
* All fields of the table
*/
public static final String[] ALL = {
NAME,
PASSWORD,
SERVER
};
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.db;
import android.provider.BaseColumns;
@ -29,17 +29,17 @@ import android.provider.BaseColumns;
*/
public interface CommandConstants extends BaseColumns
{
public static final String TABLE_NAME = "commands";
// fields
public static final String COMMAND = "command";
public static final String SERVER = "server";
/**
* All fields of the table
*/
public static final String[] ALL = {
COMMAND,
SERVER
};
public static final String TABLE_NAME = "commands";
// fields
public static final String COMMAND = "command";
public static final String SERVER = "server";
/**
* All fields of the table
*/
public static final String[] ALL = {
COMMAND,
SERVER
};
}

View File

@ -0,0 +1,682 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.db;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.yaaic.model.Authentication;
import org.yaaic.model.Identity;
import org.yaaic.model.Server;
import org.yaaic.model.Status;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Database Helper for the servers and channels tables
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class Database extends SQLiteOpenHelper
{
private static final String DATABASE_NAME = "servers.db";
private static final int DATABASE_VERSION = 5;
/**
* Create a new helper for database access
*
* @param context
*/
public Database(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
/**
* Create all needed tables on first start
*/
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL("CREATE TABLE " + ServerConstants.TABLE_NAME + " ( "
+ ServerConstants._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ ServerConstants.TITLE + " TEXT NOT NULL, "
+ ServerConstants.HOST + " TEXT NOT NULL, "
+ ServerConstants.PORT + " INTEGER, "
+ ServerConstants.PASSWORD + " TEXT, "
+ ServerConstants.AUTOCONNECT + " BOOLEAN, "
+ ServerConstants.USE_SSL + " BOOLEAN, "
+ ServerConstants.CHARSET + " TEXT, "
+ ServerConstants.IDENTITY + " INTEGER, "
+ ServerConstants.NICKSERV_PASSWORD + " TEXT, "
+ ServerConstants.SASL_USERNAME + " TEXT, "
+ ServerConstants.SASL_PASSWORD + " TEXT"
+ ");"
);
db.execSQL("CREATE TABLE " + ChannelConstants.TABLE_NAME + " ("
+ ChannelConstants._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ ChannelConstants.NAME + " TEXT NOT NULL, "
+ ChannelConstants.PASSWORD + " TEXT, "
+ ChannelConstants.SERVER + " INTEGER"
+ ");"
);
db.execSQL("CREATE TABLE " + IdentityConstants.TABLE_NAME +" ("
+ IdentityConstants._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ IdentityConstants.NICKNAME + " TEXT NOT NULL,"
+ IdentityConstants.IDENT + " TEXT NOT NULL,"
+ IdentityConstants.REALNAME + " TEXT NOT NULL"
+ ");"
);
db.execSQL("CREATE TABLE " + CommandConstants.TABLE_NAME + " ("
+ CommandConstants._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ CommandConstants.COMMAND + " TEXT NOT NULL, "
+ ChannelConstants.SERVER + " INTEGER"
+ ");"
);
db.execSQL("CREATE TABLE " + AliasConstants.TABLE_NAME + " ("
+ AliasConstants._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ AliasConstants.ALIAS + " TEXT NOT NULL, "
+ AliasConstants.IDENTITY + " INTEGER"
+ ");"
);
}
/**
* Migrate existing databases to
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
// XXX: Do not delete databases (release version)
// db.execSQL("DROP TABLE IF EXISTS " + ServerConstants.TABLE_NAME + ";");
// db.execSQL("DROP TABLE IF EXISTS " + ChannelConstants.TABLE_NAME + ";");
// db.execSQL("DROP TABLE IF EXISTS " + IdentityConstants.TABLE_NAME + ";");
// onCreate(db);
if (oldVersion == 1) {
// Add charset field to server table
db.execSQL("ALTER TABLE " + ServerConstants.TABLE_NAME + " ADD " + ServerConstants.CHARSET + " TEXT AFTER " + ServerConstants.USE_SSL + ";");
oldVersion = 2; // now do the updates for version 2
}
if (oldVersion == 2) {
// Add new commands table (copy&paste from onCreate())
db.execSQL("CREATE TABLE " + CommandConstants.TABLE_NAME + " ("
+ CommandConstants._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ CommandConstants.COMMAND + " TEXT NOT NULL, "
+ ChannelConstants.SERVER + " INTEGER"
+ ");"
);
oldVersion = 3;
}
if (oldVersion == 3) {
db.execSQL("CREATE TABLE " + AliasConstants.TABLE_NAME + " ("
+ AliasConstants._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ AliasConstants.ALIAS + " TEXT NOT NULL, "
+ AliasConstants.IDENTITY + " INTEGER"
+ ");"
);
oldVersion = 4;
}
if (oldVersion == 4) {
// Add authentication fields to database
db.execSQL("ALTER TABLE " + ServerConstants.TABLE_NAME + " ADD " + ServerConstants.NICKSERV_PASSWORD + " TEXT AFTER " + ServerConstants.CHARSET + ";");
db.execSQL("ALTER TABLE " + ServerConstants.TABLE_NAME + " ADD " + ServerConstants.SASL_USERNAME + " TEXT AFTER " + ServerConstants.NICKSERV_PASSWORD + ";");
db.execSQL("ALTER TABLE " + ServerConstants.TABLE_NAME + " ADD " + ServerConstants.SASL_PASSWORD + " TEXT AFTER " + ServerConstants.SASL_USERNAME + ";");
}
}
/**
* Add a new server to the database
*
* @param server The server to add.
* @param identityId The id of the assigned identity
*/
public long addServer(Server server, int identityId)
{
ContentValues values = new ContentValues();
values.put(ServerConstants.TITLE, server.getTitle());
values.put(ServerConstants.HOST, server.getHost());
values.put(ServerConstants.PORT, server.getPort());
values.put(ServerConstants.PASSWORD, server.getPassword());
values.put(ServerConstants.AUTOCONNECT, false);
values.put(ServerConstants.USE_SSL, server.useSSL());
values.put(ServerConstants.IDENTITY, identityId);
values.put(ServerConstants.CHARSET, server.getCharset());
Authentication authentication = server.getAuthentication();
values.put(ServerConstants.NICKSERV_PASSWORD, authentication.getNickservPassword());
values.put(ServerConstants.SASL_USERNAME, authentication.getSaslUsername());
values.put(ServerConstants.SASL_PASSWORD, authentication.getSaslPassword());
return this.getWritableDatabase().insert(ServerConstants.TABLE_NAME, null, values);
}
/**
* Update the server record in the database
*
* @param serverId The primary key of the server to update.
* @param server The server to update.
* @param identityId The identity of the server record
*/
public void updateServer(int serverId, Server server, int identityId)
{
ContentValues values = new ContentValues();
values.put(ServerConstants.TITLE, server.getTitle());
values.put(ServerConstants.HOST, server.getHost());
values.put(ServerConstants.PORT, server.getPort());
values.put(ServerConstants.PASSWORD, server.getPassword());
values.put(ServerConstants.AUTOCONNECT, false);
values.put(ServerConstants.USE_SSL, server.useSSL());
values.put(ServerConstants.IDENTITY, identityId);
values.put(ServerConstants.CHARSET, server.getCharset());
Authentication authentication = server.getAuthentication();
values.put(ServerConstants.NICKSERV_PASSWORD, authentication.getNickservPassword());
values.put(ServerConstants.SASL_USERNAME, authentication.getSaslUsername());
values.put(ServerConstants.SASL_PASSWORD, authentication.getSaslPassword());
this.getWritableDatabase().update(
ServerConstants.TABLE_NAME,
values,
ServerConstants._ID + " = " + serverId,
null
);
}
/**
* Add a channel to the database
*
* @param serverId Unique id of server
* @param name Name of channel
* @param password Password to join (if needed)
*/
public void addChannel(int serverId, String name, String password)
{
ContentValues values = new ContentValues();
values.put(ChannelConstants.NAME, name);
values.put(ChannelConstants.PASSWORD, password);
values.put(ChannelConstants.SERVER, serverId);
this.getWritableDatabase().insert(ChannelConstants.TABLE_NAME, null, values);
}
/**
* Replace list of channels for the given server
*
* @param serverId Unique id of server
* @param channels List of channel names
*/
public void setChannels(int serverId, ArrayList<String> channels)
{
// Remove old channels
this.getWritableDatabase().delete(
ChannelConstants.TABLE_NAME,
ChannelConstants.SERVER + " = " + serverId,
null
);
// Add new channels
for (String channel : channels) {
addChannel(serverId, channel, "");
}
}
/**
* Get all commands to execute on connect
*
* @param serverId Unique id of server
* @return List of commands
*/
public ArrayList<String> getCommandsByServerId(int serverId)
{
ArrayList<String> commands = new ArrayList<String>();
Cursor cursor = this.getReadableDatabase().query(
CommandConstants.TABLE_NAME,
CommandConstants.ALL,
CommandConstants.SERVER + " = " + serverId,
null,
null,
null,
null
);
while (cursor.moveToNext()) {
String command = cursor.getString(cursor.getColumnIndex(CommandConstants.COMMAND));
commands.add(command);
}
cursor.close();
return commands;
}
/**
* Add a command to a server
*
* @param serverId Unique id of server
* @param command The command to execute after connect
*/
public void addCommand(int serverId, String command)
{
ContentValues values = new ContentValues();
values.put(CommandConstants.COMMAND, command);
values.put(CommandConstants.SERVER, serverId);
this.getWritableDatabase().insert(CommandConstants.TABLE_NAME, null, values);
}
/**
* Replace list of commands for the given server
*
* @param serverId Unique id of server
* @param commands List of commands to execute after connect
*/
public void setCommands(int serverId, ArrayList<String> commands)
{
// Remove old commands
this.getWritableDatabase().delete(
CommandConstants.TABLE_NAME,
CommandConstants.SERVER + " = " + serverId,
null
);
// Add new commands
for (String command : commands) {
addCommand(serverId, command);
}
}
/**
* Get all servers from database
*
* @return
*/
public HashMap<Integer, Server> getServers()
{
HashMap<Integer, Server> servers = new HashMap<Integer, Server>();
Cursor cursor = this.getReadableDatabase().query(
ServerConstants.TABLE_NAME,
ServerConstants.ALL,
null,
null,
null,
null,
ServerConstants.TITLE + " ASC"
);
while (cursor.moveToNext()) {
Server server = populateServer(cursor);
servers.put(server.getId(), server);
}
cursor.close();
return servers;
}
public Server getServerById(int serverId)
{
Server server = null;
Cursor cursor = this.getReadableDatabase().query(
ServerConstants.TABLE_NAME,
ServerConstants.ALL,
ServerConstants._ID + " = " + serverId,
null,
null,
null,
ServerConstants.TITLE + " ASC"
);
if (cursor.moveToNext()) {
server = populateServer(cursor);
}
cursor.close();
return server;
}
/**
* Check if the given server title is currently used
*
* @param title The server title
* @return true if there's a server with this title, false otherwise
*/
public boolean isTitleUsed(String title)
{
boolean isTitleUsed = false;
Cursor cursor = this.getReadableDatabase().query(
ServerConstants.TABLE_NAME,
ServerConstants.ALL,
ServerConstants.TITLE + " = " + DatabaseUtils.sqlEscapeString(title),
null,
null,
null,
null
);
if (cursor.moveToNext()) {
isTitleUsed = true;
}
cursor.close();
return isTitleUsed;
}
/**
* Populate a server object from the given database cursor
* @param cursor
* @return
*/
private Server populateServer(Cursor cursor)
{
Server server = new Server();
server.setTitle(cursor.getString(cursor.getColumnIndex((ServerConstants.TITLE))));
server.setHost(cursor.getString(cursor.getColumnIndex((ServerConstants.HOST))));
server.setPort(cursor.getInt(cursor.getColumnIndex((ServerConstants.PORT))));
server.setPassword(cursor.getString(cursor.getColumnIndex(ServerConstants.PASSWORD)));
server.setId(cursor.getInt(cursor.getColumnIndex((ServerConstants._ID))));
server.setCharset(cursor.getString(cursor.getColumnIndex(ServerConstants.CHARSET)));
String useSSLvalue = cursor.getString(cursor.getColumnIndex(ServerConstants.USE_SSL));
if (useSSLvalue != null && useSSLvalue.equals("1")) {
server.setUseSSL(true);
}
server.setStatus(Status.DISCONNECTED);
Authentication authentication = new Authentication();
authentication.setNickservPassword(cursor.getString(cursor.getColumnIndex(ServerConstants.NICKSERV_PASSWORD)));
authentication.setSaslUsername(cursor.getString(cursor.getColumnIndex(ServerConstants.SASL_USERNAME)));
authentication.setSaslPassword(cursor.getString(cursor.getColumnIndex(ServerConstants.SASL_PASSWORD)));
server.setAuthentication(authentication);
// Load identity for server
Identity identity = this.getIdentityById(cursor.getInt(cursor.getColumnIndex(ServerConstants.IDENTITY)));
server.setIdentity(identity);
// Load auto join channels
ArrayList<String> channels = this.getChannelsByServerId(server.getId());
server.setAutoJoinChannels(channels);
// Load commands to execute after connect
ArrayList<String> commands = this.getCommandsByServerId(server.getId());
server.setConnectCommands(commands);
return server;
}
/**
* Get all servers with autoconnect enabled
*
* @return
*/
public Cursor getAutoConnectServers()
{
return this.getReadableDatabase().query(
ServerConstants.TABLE_NAME,
ServerConstants.ALL,
ServerConstants.AUTOCONNECT + " = 1",
null,
null,
null,
ServerConstants.TITLE + " ASC"
);
}
/**
* Get all channels of server
*
* @param server Unique id of server
* @return list of channel names
*/
public ArrayList<String> getChannelsByServerId(int serverId)
{
ArrayList<String> channels = new ArrayList<String>();
Cursor cursor = this.getReadableDatabase().query(
ChannelConstants.TABLE_NAME,
ChannelConstants.ALL,
ChannelConstants.SERVER + " = " + serverId,
null,
null,
null,
ChannelConstants.NAME + " ASC"
);
while (cursor.moveToNext()) {
String channel = cursor.getString(cursor.getColumnIndex(ChannelConstants.NAME));
channels.add(channel);
}
cursor.close();
return channels;
}
/**
* Remove server from database by unique id
*
* @param title
*/
public void removeServerById(int serverId)
{
// XXX: Workaround: Remove identity assigned to this server
// until we have some kind of identity manager
int identityId = this.getIdentityIdByServerId(serverId);
if (identityId != -1) {
deleteAliases(identityId);
this.getWritableDatabase().execSQL(
"DELETE FROM " + IdentityConstants.TABLE_NAME + " WHERE " + IdentityConstants._ID + " = " + identityId + ";"
);
}
// Now delete the server entry
this.getWritableDatabase().execSQL(
"DELETE FROM " + ServerConstants.TABLE_NAME + " WHERE " + ServerConstants._ID + " = " + serverId + ";"
);
}
protected void setAliases(long identityId, List<String> aliases)
{
deleteAliases(identityId);
ContentValues values = new ContentValues();
for (String alias : aliases) {
values.clear();
values.put(AliasConstants.ALIAS, alias);
values.put(AliasConstants.IDENTITY, identityId);
getWritableDatabase().insert(AliasConstants.TABLE_NAME, null, values);
}
}
protected void deleteAliases(long identityId)
{
getWritableDatabase().execSQL(
"DELETE FROM " + AliasConstants.TABLE_NAME + " WHERE " + AliasConstants.IDENTITY + " = " + identityId
);
}
protected List<String> getAliasesByIdentityId(long identityId)
{
List<String> aliases = new ArrayList<String>();
Cursor cursor = this.getReadableDatabase().query(
AliasConstants.TABLE_NAME,
AliasConstants.ALL,
AliasConstants.IDENTITY + " = " + identityId,
null,
null,
null,
null
);
while (cursor.moveToNext()) {
aliases.add(cursor.getString(cursor.getColumnIndex(AliasConstants.ALIAS)));
}
cursor.close();
return aliases;
}
/**
* Add a new identity
*
* @param identityId
* @param nickname
* @param ident
* @param realname
* @param aliases
*/
public long addIdentity(String nickname, String ident, String realname, List<String> aliases)
{
ContentValues values = new ContentValues();
values.put(IdentityConstants.NICKNAME, nickname);
values.put(IdentityConstants.IDENT, ident);
values.put(IdentityConstants.REALNAME, realname);
long identityId = this.getWritableDatabase().insert(IdentityConstants.TABLE_NAME, null, values);
setAliases(identityId, aliases);
return identityId;
}
/**
* Update the identity with the given id
*
* @param identityId
* @param nickname
* @param ident
* @param realname
*/
public void updateIdentity(int identityId, String nickname, String ident, String realname, List<String> aliases)
{
ContentValues values = new ContentValues();
values.put(IdentityConstants.NICKNAME, nickname);
values.put(IdentityConstants.IDENT, ident);
values.put(IdentityConstants.REALNAME, realname);
this.getWritableDatabase().update(
IdentityConstants.TABLE_NAME,
values,
IdentityConstants._ID + " = " + identityId,
null
);
setAliases(identityId, aliases);
}
/**
* Get an identity by its id
*
* @param identityId
* @return
*/
public Identity getIdentityById(int identityId)
{
Identity identity = null;
Cursor cursor = this.getReadableDatabase().query(
IdentityConstants.TABLE_NAME,
IdentityConstants.ALL,
IdentityConstants._ID + "=" + identityId,
null,
null,
null,
null
);
if (cursor.moveToNext()) {
identity = new Identity();
identity.setNickname(cursor.getString(cursor.getColumnIndex(IdentityConstants.NICKNAME)));
identity.setIdent(cursor.getString(cursor.getColumnIndex(IdentityConstants.IDENT)));
identity.setRealName(cursor.getString(cursor.getColumnIndex(IdentityConstants.REALNAME)));
identity.setAliases(getAliasesByIdentityId(identityId));
}
cursor.close();
return identity;
}
/**
* Get a server by its id
*
* @param serverId
* @return
*/
public int getIdentityIdByServerId(int serverId)
{
int identityId = -1;
Cursor cursor = this.getReadableDatabase().query(
ServerConstants.TABLE_NAME,
ServerConstants.ALL,
ServerConstants._ID + " = " + serverId,
null,
null,
null,
null
);
if (cursor.moveToNext()) {
identityId = cursor.getInt(cursor.getColumnIndex(ServerConstants.IDENTITY));
}
cursor.close();
return identityId;
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,32 +17,32 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.db;
import android.provider.BaseColumns;
/**
* Constants for the identity table
*
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class IdentityConstants implements BaseColumns
{
public static final String TABLE_NAME = "identities";
// fields
public static final String NICKNAME = "nickname";
public static final String IDENT = "ident";
public static final String REALNAME = "realname";
/**
* All fields of the table
*/
public static final String[] ALL = {
_ID,
NICKNAME,
IDENT,
REALNAME,
};
public static final String TABLE_NAME = "identities";
// fields
public static final String NICKNAME = "nickname";
public static final String IDENT = "ident";
public static final String REALNAME = "realname";
/**
* All fields of the table
*/
public static final String[] ALL = {
_ID,
NICKNAME,
IDENT,
REALNAME,
};
}

View File

@ -0,0 +1,64 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.db;
import android.provider.BaseColumns;
/**
* Constants for the server table
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public interface ServerConstants extends BaseColumns
{
public static final String TABLE_NAME = "servers";
// fields
public static final String TITLE = "title";
public static final String HOST = "host";
public static final String PORT = "port";
public static final String PASSWORD = "password";
public static final String AUTOCONNECT = "autoConnect";
public static final String USE_SSL = "useSSL";
public static final String CHARSET = "charset";
public static final String IDENTITY = "identity";
public static final String NICKSERV_PASSWORD = "nickserv_password";
public static final String SASL_USERNAME = "sasl_username";
public static final String SASL_PASSWORD = "sasl_password";
/**
* All fields of the table
*/
public static final String[] ALL = {
_ID,
TITLE,
HOST,
PORT,
PASSWORD,
AUTOCONNECT,
USE_SSL,
CHARSET,
IDENTITY,
NICKSERV_PASSWORD,
SASL_USERNAME,
SASL_PASSWORD
};
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.exception;
/**
@ -28,13 +28,13 @@ package org.yaaic.exception;
*/
public class CommandException extends Throwable
{
private static final long serialVersionUID = -8317993941455253288L;
/**
* Create a new CommandException object
*/
public CommandException(String message)
{
super(message);
}
private static final long serialVersionUID = -8317993941455253288L;
/**
* Create a new CommandException object
*/
public CommandException(String message)
{
super(message);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,25 +17,25 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.exception;
/**
* A valiadtion exception is thrown if any user input is invalid
* A ValidationException is thrown if any user input is invalid
*
* @author Sebastian Kaspari
*/
public class ValidationException extends Exception
{
private static final long serialVersionUID = 6951535205062761539L;
/**
* Create a new ValidationException with the given message
*
* @param message The error message
*/
public ValidationException(String message)
{
super(message);
}
private static final long serialVersionUID = 6951535205062761539L;
/**
* Create a new ValidationException with the given message
*
* @param message The error message
*/
public ValidationException(String message)
{
super(message);
}
}

View File

@ -0,0 +1,921 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2015 Sebastian Kaspari
Copyright 2012 Daniel E. Moctezuma <democtezuma@gmail.com>
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.fragment;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.speech.RecognizerIntent;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.Toolbar;
import android.text.InputType;
import android.text.method.TextKeyListener;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
import org.yaaic.R;
import org.yaaic.Yaaic;
import org.yaaic.activity.JoinActivity;
import org.yaaic.activity.UserActivity;
import org.yaaic.activity.UsersActivity;
import org.yaaic.activity.YaaicActivity;
import org.yaaic.adapter.ConversationPagerAdapter;
import org.yaaic.adapter.MessageListAdapter;
import org.yaaic.command.CommandParser;
import org.yaaic.irc.IRCBinder;
import org.yaaic.irc.IRCConnection;
import org.yaaic.irc.IRCService;
import org.yaaic.listener.ConversationListener;
import org.yaaic.listener.ServerListener;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Extra;
import org.yaaic.model.Message;
import org.yaaic.model.Query;
import org.yaaic.model.Scrollback;
import org.yaaic.model.Server;
import org.yaaic.model.ServerInfo;
import org.yaaic.model.Settings;
import org.yaaic.model.Status;
import org.yaaic.model.User;
import org.yaaic.receiver.ConversationReceiver;
import org.yaaic.receiver.ServerReceiver;
import org.yaaic.view.ConversationTabLayout;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* The server view with a scrollable pager of all conversations.
*/
public class ConversationFragment extends Fragment implements ServerListener, ConversationListener, ServiceConnection {
public static final String TRANSACTION_TAG = "fragment_conversation";
private static final int REQUEST_CODE_JOIN = 1;
private static final int REQUEST_CODE_USERS = 2;
private static final int REQUEST_CODE_USER = 3;
private static final int REQUEST_CODE_NICK_COMPLETION= 4;
private int serverId;
private Server server;
private IRCBinder binder;
private ConversationReceiver channelReceiver;
private ServerReceiver serverReceiver;
private YaaicActivity activity;
private EditText input;
private ViewPager pager;
private ConversationPagerAdapter pagerAdapter;
private ConversationTabLayout tabLayout;
private Scrollback scrollback;
// XXX: This is ugly. This is a buffer for a channel that should be joined after showing the
// JoinActivity. As onActivityResult() is called before onResume() a "channel joined"
// broadcast may get lost as the broadcast receivers are registered in onResume() but the
// join command would be called in onActivityResult(). joinChannelBuffer will save the
// channel name in onActivityResult() and run the join command in onResume().
private String joinChannelBuffer;
private boolean reconnectDialogActive = false;
private final View.OnKeyListener inputKeyListener = new View.OnKeyListener() {
/**
* On key pressed (input line)
*/
@Override
public boolean onKey(View view, int keyCode, KeyEvent event) {
EditText input = (EditText) view;
if (event.getAction() != KeyEvent.ACTION_DOWN) {
return false;
}
if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
String message = scrollback.goBack();
if (message != null) {
input.setText(message);
}
return true;
}
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
String message = scrollback.goForward();
if (message != null) {
input.setText(message);
}
return true;
}
if (keyCode == KeyEvent.KEYCODE_ENTER) {
sendCurrentMessage();
return true;
}
// Nick completion
if (keyCode == KeyEvent.KEYCODE_SEARCH) {
doNickCompletion(input);
return true;
}
return false;
}
};
public ConversationFragment() {
setHasOptionsMenu(true);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof YaaicActivity)) {
throw new IllegalArgumentException("Activity has to implement YaaicActivity interface");
}
this.activity = (YaaicActivity) activity;
}
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
serverId = getArguments().getInt("serverId");
server = Yaaic.getInstance().getServerById(serverId);
scrollback = new Scrollback();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_conversations, container, false);
Settings settings = new Settings(getActivity());
boolean isLandscape = (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE);
input = (EditText) view.findViewById(R.id.input);
input.setOnKeyListener(inputKeyListener);
pager = (ViewPager) view.findViewById(R.id.pager);
pagerAdapter = new ConversationPagerAdapter(getActivity(), server);
pager.setAdapter(pagerAdapter);
tabLayout = new ConversationTabLayout(container.getContext());
tabLayout.setViewPager(pager);
tabLayout.setSelectedIndicatorColors(getResources().getColor(R.color.accent));
tabLayout.setDividerColors(getResources().getColor(R.color.divider));
Toolbar.LayoutParams params = new Toolbar.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
);
params.gravity = Gravity.BOTTOM;
activity.getToolbar().addView(tabLayout, params);
if (server.getStatus() == Status.PRE_CONNECTING) {
server.clearConversations();
pagerAdapter.clearConversations();
server.getConversation(ServerInfo.DEFAULT_NAME).setHistorySize(
settings.getHistorySize()
);
}
// Optimization : cache field lookups
Collection<Conversation> mConversations = server.getConversations();
for (Conversation conversation : mConversations) {
// Only scroll to new conversation if it was selected before
if (conversation.getStatus() == Conversation.STATUS_SELECTED) {
onNewConversation(conversation.getName());
} else {
createNewConversation(conversation.getName());
}
}
int setInputTypeFlags = 0;
setInputTypeFlags |= InputType.TYPE_TEXT_FLAG_AUTO_CORRECT;
if (settings.autoCapSentences()) {
setInputTypeFlags |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
}
if (isLandscape && settings.imeExtract()) {
setInputTypeFlags |= InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE;
}
if (!settings.imeExtract()) {
input.setImeOptions(input.getImeOptions() | EditorInfo.IME_FLAG_NO_EXTRACT_UI);
}
input.setInputType(input.getInputType() | setInputTypeFlags);
ImageButton sendButton = (ImageButton) view.findViewById(R.id.send);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (input.getText().length() > 0) {
sendCurrentMessage();
}
}
});
sendButton.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
doNickCompletion(input);
return true;
}
});
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
activity.getToolbar().removeView(tabLayout);
}
/**
* On resume
*/
@Override
public void onResume() {
// register the receivers as early as possible, otherwise we may loose a broadcast message
channelReceiver = new ConversationReceiver(server.getId(), this);
getActivity().registerReceiver(channelReceiver, new IntentFilter(Broadcast.CONVERSATION_MESSAGE));
getActivity().registerReceiver(channelReceiver, new IntentFilter(Broadcast.CONVERSATION_NEW));
getActivity().registerReceiver(channelReceiver, new IntentFilter(Broadcast.CONVERSATION_REMOVE));
getActivity().registerReceiver(channelReceiver, new IntentFilter(Broadcast.CONVERSATION_TOPIC));
serverReceiver = new ServerReceiver(this);
getActivity().registerReceiver(serverReceiver, new IntentFilter(Broadcast.SERVER_UPDATE));
super.onResume();
// Start service
Intent intent = new Intent(getActivity(), IRCService.class);
intent.setAction(IRCService.ACTION_FOREGROUND);
getActivity().startService(intent);
getActivity().bindService(intent, this, 0);
input.setEnabled(server.isConnected());
// Optimization - cache field lookup
Collection<Conversation> mConversations = server.getConversations();
MessageListAdapter mAdapter;
// Fill view with messages that have been buffered while paused
for (Conversation conversation : mConversations) {
String name = conversation.getName();
mAdapter = pagerAdapter.getItemAdapter(name);
if (mAdapter != null) {
mAdapter.addBulkMessages(conversation.getBuffer());
conversation.clearBuffer();
} else {
// Was conversation created while we were paused?
if (pagerAdapter.getPositionByName(name) == -1) {
onNewConversation(name);
}
}
// Clear new message notifications for the selected conversation
if (conversation.getStatus() == Conversation.STATUS_SELECTED && conversation.getNewMentions() > 0) {
Intent ackIntent = new Intent(getActivity(), IRCService.class);
ackIntent.setAction(IRCService.ACTION_ACK_NEW_MENTIONS);
ackIntent.putExtra(IRCService.EXTRA_ACK_SERVERID, serverId);
ackIntent.putExtra(IRCService.EXTRA_ACK_CONVTITLE, name);
getActivity().startService(ackIntent);
}
}
// Remove views for conversations that ended while we were paused
int numViews = pagerAdapter.getCount();
if (numViews > mConversations.size()) {
for (int i = 0; i < numViews; ++i) {
if (!mConversations.contains(pagerAdapter.getItem(i))) {
pagerAdapter.removeConversation(i--);
--numViews;
}
}
}
// Join channel that has been selected in JoinActivity (onActivityResult())
if (joinChannelBuffer != null) {
new Thread() {
@Override
public void run() {
binder.getService().getConnection(serverId).joinChannel(joinChannelBuffer);
joinChannelBuffer = null;
}
}.start();
}
server.setIsForeground(true);
}
/**
* On Pause
*/
@Override
public void onPause() {
super.onPause();
server.setIsForeground(false);
if (binder != null && binder.getService() != null) {
binder.getService().checkServiceStatus();
}
getActivity().unbindService(this);
getActivity().unregisterReceiver(channelReceiver);
getActivity().unregisterReceiver(serverReceiver);
}
/**
* On service connected
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
this.binder = (IRCBinder) service;
// connect to irc server if connect has been requested
if (server.getStatus() == Status.PRE_CONNECTING && getArguments().containsKey("connect")) {
server.setStatus(Status.CONNECTING);
binder.connect(server);
} else {
onStatusUpdate();
}
}
/**
* On service disconnected
*/
@Override
public void onServiceDisconnected(ComponentName name) {
this.binder = null;
}
/**
* On options menu requested
*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.conversations, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.disconnect:
server.setStatus(Status.DISCONNECTED);
server.setMayReconnect(false);
binder.getService().getConnection(serverId).quitServer();
server.clearConversations();
break;
case R.id.close:
Conversation conversationToClose = pagerAdapter.getItem(pager.getCurrentItem());
// Make sure we part a channel when closing the channel conversation
if (conversationToClose.getType() == Conversation.TYPE_CHANNEL) {
binder.getService().getConnection(serverId).partChannel(conversationToClose.getName());
}
else if (conversationToClose.getType() == Conversation.TYPE_QUERY) {
server.removeConversation(conversationToClose.getName());
onRemoveConversation(conversationToClose.getName());
} else {
Toast.makeText(getActivity(), getResources().getString(R.string.close_server_window), Toast.LENGTH_SHORT).show();
}
break;
case R.id.join:
startActivityForResult(new Intent(getActivity(), JoinActivity.class), REQUEST_CODE_JOIN);
break;
case R.id.users:
Conversation conversationForUserList = pagerAdapter.getItem(pager.getCurrentItem());
if (conversationForUserList.getType() == Conversation.TYPE_CHANNEL) {
Intent intent = new Intent(getActivity(), UsersActivity.class);
intent.putExtra(
Extra.USERS,
binder.getService().getConnection(server.getId()).getUsersAsStringArray(
conversationForUserList.getName()
)
);
startActivityForResult(intent, REQUEST_CODE_USERS);
} else {
Toast.makeText(getActivity(), getResources().getString(R.string.only_usable_from_channel), Toast.LENGTH_SHORT).show();
}
break;
}
return true;
}
/**
* Get server object assigned to this activity
*
* @return the server object
*/
public Server getServer() {
return server;
}
/**
* On conversation message
*/
@Override
public void onConversationMessage(String target) {
Conversation conversation = server.getConversation(target);
if (conversation == null) {
// In an early state it can happen that the conversation object
// is not created yet.
return;
}
MessageListAdapter adapter = pagerAdapter.getItemAdapter(target);
while(conversation.hasBufferedMessages()) {
Message message = conversation.pollBufferedMessage();
if (adapter != null && message != null) {
adapter.addMessage(message);
int status;
switch (message.getType())
{
case Message.TYPE_MISC:
status = Conversation.STATUS_MISC;
break;
default:
status = Conversation.STATUS_MESSAGE;
break;
}
conversation.setStatus(status);
}
}
}
/**
* On new conversation
*/
@Override
public void onNewConversation(String target) {
createNewConversation(target);
pager.setCurrentItem(pagerAdapter.getCount() - 1);
}
/**
* Create a new conversation in the pager adapter for the
* given target conversation.
*
* @param target
*/
public void createNewConversation(String target) {
pagerAdapter.addConversation(server.getConversation(target));
tabLayout.update();
}
/**
* On conversation remove
*/
@Override
public void onRemoveConversation(String target) {
int position = pagerAdapter.getPositionByName(target);
if (position != -1) {
pagerAdapter.removeConversation(position);
}
tabLayout.update();
}
/**
* On topic change
*/
@Override
public void onTopicChanged(String target) {
// No implementation
}
/**
* On server status update
*/
@Override
public void onStatusUpdate() {
if (server.isConnected()) {
input.setEnabled(true);
} else {
input.setEnabled(false);
if (server.getStatus() == Status.CONNECTING) {
return;
}
// Service is not connected or initialized yet - See #54
if (binder == null || binder.getService() == null || binder.getService().getSettings() == null) {
return;
}
if (!binder.getService().getSettings().isReconnectEnabled() && !reconnectDialogActive) {
reconnectDialogActive = true;
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(getResources().getString(R.string.reconnect_after_disconnect, server.getTitle()))
.setCancelable(false)
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
if (!server.isDisconnected()) {
reconnectDialogActive = false;
return;
}
binder.getService().getConnection(server.getId()).setAutojoinChannels(
server.getCurrentChannelNames()
);
server.setStatus(Status.CONNECTING);
binder.connect(server);
reconnectDialogActive = false;
}
})
.setNegativeButton(getString(R.string.negative_button), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
server.setMayReconnect(false);
reconnectDialogActive = false;
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
}
/**
* On activity result
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode != Activity.RESULT_OK) {
// ignore other result codes
return;
}
switch (requestCode) {
case REQUEST_CODE_JOIN:
joinChannelBuffer = data.getExtras().getString("channel");
break;
case REQUEST_CODE_USERS:
Intent intent = new Intent(getActivity(), UserActivity.class);
intent.putExtra(Extra.USER, data.getStringExtra(Extra.USER));
startActivityForResult(intent, REQUEST_CODE_USER);
break;
case REQUEST_CODE_NICK_COMPLETION:
insertNickCompletion(input, data.getExtras().getString(Extra.USER));
break;
case REQUEST_CODE_USER:
final int actionId = data.getExtras().getInt(Extra.ACTION);
final String nickname = data.getExtras().getString(Extra.USER);
final IRCConnection connection = binder.getService().getConnection(server.getId());
final String conversation = server.getSelectedConversation();
final Handler handler = new Handler();
// XXX: Implement me - The action should be handled after onResume()
// to catch the broadcasts... now we just wait a second
// Yes .. that's very ugly - we need some kind of queue that is handled after onResume()
new Thread() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// Do nothing
}
String nicknameWithoutPrefix = nickname;
while (
nicknameWithoutPrefix.startsWith("@") ||
nicknameWithoutPrefix.startsWith("+") ||
nicknameWithoutPrefix.startsWith(".") ||
nicknameWithoutPrefix.startsWith("%")
) {
// Strip prefix(es) now
nicknameWithoutPrefix = nicknameWithoutPrefix.substring(1);
}
switch (actionId) {
case User.ACTION_REPLY:
final String replyText = nicknameWithoutPrefix + ": ";
handler.post(new Runnable() {
@Override
public void run() {
input.setText(replyText);
input.setSelection(replyText.length());
}
});
break;
case User.ACTION_QUERY:
Conversation query = server.getConversation(nicknameWithoutPrefix);
if (query == null) {
// Open a query if there's none yet
query = new Query(nicknameWithoutPrefix);
query.setHistorySize(binder.getService().getSettings().getHistorySize());
server.addConversation(query);
Intent intent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_NEW,
server.getId(),
nicknameWithoutPrefix
);
binder.getService().sendBroadcast(intent);
}
break;
case User.ACTION_OP:
connection.op(conversation, nicknameWithoutPrefix);
break;
case User.ACTION_DEOP:
connection.deOp(conversation, nicknameWithoutPrefix);
break;
case User.ACTION_VOICE:
connection.voice(conversation, nicknameWithoutPrefix);
break;
case User.ACTION_DEVOICE:
connection.deVoice(conversation, nicknameWithoutPrefix);
break;
case User.ACTION_KICK:
connection.kick(conversation, nicknameWithoutPrefix);
break;
case User.ACTION_BAN:
connection.ban(conversation, nicknameWithoutPrefix + "!*@*");
break;
}
}
}.start();
break;
}
}
private void sendCurrentMessage() {
sendMessage(input.getText().toString());
// Workaround for a race condition in EditText
// Instead of calling input.setText("");
// See:
// - https://github.com/pocmo/Yaaic/issues/67
// - http://code.google.com/p/android/issues/detail?id=17508
TextKeyListener.clear(input.getText());
}
/**
* Send a message in this conversation
*
* @param text The text of the message
*/
private void sendMessage(String text) {
if (text.equals("")) {
// ignore empty messages
return;
}
if (!server.isConnected()) {
Message message = new Message(getString(R.string.message_not_connected));
message.setColor(Message.COLOR_RED);
message.setIcon(R.drawable.error);
server.getConversation(server.getSelectedConversation()).addMessage(message);
onConversationMessage(server.getSelectedConversation());
}
scrollback.addMessage(text);
Conversation conversation = pagerAdapter.getItem(pager.getCurrentItem());
if (conversation != null) {
if (!text.trim().startsWith("/")) {
if (conversation.getType() != Conversation.TYPE_SERVER) {
String nickname = binder.getService().getConnection(serverId).getNick();
//conversation.addMessage(new Message("<" + nickname + "> " + text));
conversation.addMessage(new Message(text, nickname));
binder.getService().getConnection(serverId).sendMessage(conversation.getName(), text);
} else {
Message message = new Message(getString(R.string.chat_only_form_channel));
message.setColor(Message.COLOR_YELLOW);
message.setIcon(R.drawable.warning);
conversation.addMessage(message);
}
onConversationMessage(conversation.getName());
} else {
CommandParser.getInstance().parse(text, server, conversation, binder.getService());
}
}
}
/**
* Complete a nick in the input line
*/
private void doNickCompletion(EditText input) {
String text = input.getText().toString();
if (text.length() <= 0) {
return;
}
String[] tokens = text.split("[\\s,.-]+");
if (tokens.length <= 0) {
return;
}
String word = tokens[tokens.length - 1].toLowerCase();
tokens[tokens.length - 1] = null;
int begin = input.getSelectionStart();
int end = input.getSelectionEnd();
int cursor = Math.min(begin, end);
int sel_end = Math.max(begin, end);
boolean in_selection = (cursor != sel_end);
if (in_selection) {
word = text.substring(cursor, sel_end);
} else {
// use the word at the curent cursor position
while (true) {
cursor -= 1;
if (cursor <= 0 || text.charAt(cursor) == ' ') {
break;
}
}
if (cursor < 0) {
cursor = 0;
}
if (text.charAt(cursor) == ' ') {
cursor += 1;
}
sel_end = text.indexOf(' ', cursor);
if (sel_end == -1) {
sel_end = text.length();
}
word = text.substring(cursor, sel_end);
}
// Log.d("Yaaic", "Trying to complete nick: " + word);
Conversation conversationForUserList = pagerAdapter.getItem(pager.getCurrentItem());
String[] users = null;
if (conversationForUserList.getType() == Conversation.TYPE_CHANNEL) {
users = binder.getService().getConnection(server.getId()).getUsersAsStringArray(
conversationForUserList.getName()
);
}
// go through users and add matches
if (users != null) {
List<Integer> result = new ArrayList<Integer>();
for (int i = 0; i < users.length; i++) {
String nick = removeStatusChar(users[i].toLowerCase());
if (nick.startsWith(word.toLowerCase())) {
result.add(Integer.valueOf(i));
}
}
if (result.size() == 1) {
input.setSelection(cursor, sel_end);
insertNickCompletion(input, users[result.get(0).intValue()]);
} else if (result.size() > 0) {
Intent intent = new Intent(getActivity(), UsersActivity.class);
String[] extra = new String[result.size()];
int i = 0;
for (Integer n : result) {
extra[i++] = users[n.intValue()];
}
input.setSelection(cursor, sel_end);
intent.putExtra(Extra.USERS, extra);
startActivityForResult(intent, REQUEST_CODE_NICK_COMPLETION);
}
}
}
/**
* Insert a given nick completion into the input line
*
* @param input The input line widget, with the incomplete nick selected
* @param nick The completed nick
*/
private void insertNickCompletion(final EditText input, String nick) {
int start = input.getSelectionStart();
int end = input.getSelectionEnd();
nick = removeStatusChar(nick);
if (start == 0) {
nick += ":";
}
nick += " ";
input.getText().replace(start, end, nick, 0, nick.length());
// put cursor after inserted text
input.setSelection(start + nick.length());
input.clearComposingText();
input.post(new Runnable() {
@Override
public void run() {
// make the softkeyboard come up again (only if no hw keyboard is attached)
openSoftKeyboard(input);
}
});
input.requestFocus();
}
/**
* Open the soft keyboard (helper function)
*/
private void openSoftKeyboard(View view) {
((InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE))
.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT);
}
/**
* Remove the status char off the front of a nick if one is present
*
* @param nick
* @return nick without statuschar
*/
private String removeStatusChar(String nick) {
/* Discard status characters */
if (nick.startsWith("@") || nick.startsWith("+")
|| nick.startsWith("%")) {
nick = nick.substring(1);
}
return nick;
}
}

View File

@ -0,0 +1,183 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2015 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.fragment;
import android.app.Activity;
import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.Toast;
import org.yaaic.R;
import org.yaaic.Yaaic;
import org.yaaic.activity.AddServerActivity;
import org.yaaic.activity.YaaicActivity;
import org.yaaic.adapter.ServersAdapter;
import org.yaaic.db.Database;
import org.yaaic.irc.IRCBinder;
import org.yaaic.listener.ServerListener;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Extra;
import org.yaaic.model.Server;
import org.yaaic.model.Status;
import org.yaaic.receiver.ServerReceiver;
/**
* Fragment showing a list of configured servers.
*/
public class OverviewFragment extends Fragment implements ServerListener, ServersAdapter.ClickListener, View.OnClickListener {
public static final String TRANSACTION_TAG = "fragment_overview";
private ServersAdapter adapter;
private YaaicActivity activity;
private BroadcastReceiver receiver;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof YaaicActivity)) {
throw new IllegalArgumentException("Activity has to implement YaaicActivity interface");
}
this.activity = (YaaicActivity) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity.setToolbarTitle(getString(R.string.app_name));
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_servers, container, false);
adapter = new ServersAdapter(this);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
ImageButton button = (ImageButton) view.findViewById(R.id.fab);
button.setOnClickListener(this);
return view;
}
@Override
public void onResume() {
super.onResume();
receiver = new ServerReceiver(this);
getActivity().registerReceiver(receiver, new IntentFilter(Broadcast.SERVER_UPDATE));
adapter.loadServers();
}
@Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(receiver);
}
@Override
public void onClick(View view) {
final Context context = view.getContext();
Intent intent = new Intent(context, AddServerActivity.class);
context.startActivity(intent);
}
@Override
public void onServerSelected(Server server) {
activity.onServerSelected(server);
}
@Override
public void onConnectToServer(Server server) {
IRCBinder binder = activity.getBinder();
if (binder != null && server.getStatus() == Status.DISCONNECTED) {
binder.connect(server);
server.setStatus(Status.CONNECTING);
adapter.notifyDataSetChanged();
}
}
@Override
public void onDisconnectFromServer(Server server) {
IRCBinder binder = activity.getBinder();
if (binder != null) {
server.clearConversations();
server.setStatus(Status.DISCONNECTED);
server.setMayReconnect(false);
binder.getService().getConnection(server.getId()).quitServer();
}
}
@Override
public void onEditServer(Server server) {
if (server.getStatus() != Status.DISCONNECTED) {
Toast.makeText(getActivity(), getResources().getString(R.string.disconnect_before_editing), Toast.LENGTH_SHORT).show();
} else {
Intent intent = new Intent(getActivity(), AddServerActivity.class);
intent.putExtra(Extra.SERVER, server.getId());
startActivityForResult(intent, 0);
}
}
@Override
public void onDeleteServer(Server server) {
IRCBinder binder = activity.getBinder();
if (binder != null) {
binder.getService().getConnection(server.getId()).quitServer();
Database db = new Database(getActivity());
db.removeServerById(server.getId());
db.close();
Yaaic.getInstance().removeServerById(server.getId());
adapter.loadServers();
}
}
@Override
public void onStatusUpdate() {
adapter.loadServers();
}
}

View File

@ -0,0 +1,37 @@
package org.yaaic.fragment;
import android.app.Activity;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import org.yaaic.R;
import org.yaaic.activity.YaaicActivity;
/**
* Fragment displaying all settings.
*/
public class SettingsFragment extends PreferenceFragment {
public static final String TRANSACTION_TAG = "fragment_settings";
private YaaicActivity activity;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (!(activity instanceof YaaicActivity)) {
throw new IllegalArgumentException("Activity has to implement YaaicActivity interface");
}
this.activity = (YaaicActivity) activity;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity.setToolbarTitle(getString(R.string.navigation_settings));
addPreferencesFromResource(R.xml.preferences);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.irc;
import org.yaaic.model.Server;
@ -26,41 +26,42 @@ import android.os.Binder;
/**
* Binder for service communication
*
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class IRCBinder extends Binder
{
private IRCService service;
/**
* Create a new binder for given service
*
* @param service
*/
public IRCBinder(IRCService service)
{
super();
this.service = service;
}
/**
* Connect to given server
*
* @param server
*/
public void connect(final Server server)
{
service.connect(server);
}
/**
* Get service associated with this service
* @return
*/
public IRCService getService()
{
return service;
}
private final IRCService service;
/**
* Create a new binder for given service
*
* @param service
*/
public IRCBinder(IRCService service)
{
super();
this.service = service;
}
/**
* Connect to given server
*
* @param server
*/
public void connect(final Server server)
{
service.connect(server);
}
/**
* Get service associated with this binder
*
* @return
*/
public IRCService getService()
{
return service;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,637 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
Copyright 2012 Daniel E. Moctezuma <democtezuma@gmail.com>
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.irc;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import org.jibble.pircbot.IrcException;
import org.jibble.pircbot.NickAlreadyInUseException;
import org.yaaic.R;
import org.yaaic.Yaaic;
import org.yaaic.activity.MainActivity;
import org.yaaic.db.Database;
import org.yaaic.model.Broadcast;
import org.yaaic.model.Conversation;
import org.yaaic.model.Message;
import org.yaaic.model.Server;
import org.yaaic.model.ServerInfo;
import org.yaaic.model.Settings;
import org.yaaic.model.Status;
import org.yaaic.receiver.ReconnectReceiver;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.SystemClock;
/**
* The background service for managing the irc connections
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class IRCService extends Service
{
public static final String ACTION_FOREGROUND = "org.yaaic.service.foreground";
public static final String ACTION_BACKGROUND = "org.yaaic.service.background";
public static final String ACTION_ACK_NEW_MENTIONS = "org.yaaic.service.ack_new_mentions";
public static final String EXTRA_ACK_SERVERID = "org.yaaic.service.ack_serverid";
public static final String EXTRA_ACK_CONVTITLE = "org.yaaic.service.ack_convtitle";
private static final int FOREGROUND_NOTIFICATION = 1;
private static final int NOTIFICATION_LED_OFF_MS = 1000;
private static final int NOTIFICATION_LED_ON_MS = 300;
private static final int NOTIFICATION_LED_COLOR = 0xff00ff00;
@SuppressWarnings("rawtypes")
private static final Class[] mStartForegroundSignature = new Class[] { int.class, Notification.class };
@SuppressWarnings("rawtypes")
private static final Class[] mStopForegroundSignature = new Class[] { boolean.class };
@SuppressWarnings("rawtypes")
private static final Class[] mSetForegroudSignaure = new Class[] { boolean.class };
private final IRCBinder binder;
private final HashMap<Integer, IRCConnection> connections;
private boolean foreground = false;
private final ArrayList<String> connectedServerTitles;
private final LinkedHashMap<String, Conversation> mentions;
private int newMentions = 0;
private NotificationManager notificationManager;
private Method mStartForeground;
private Method mStopForeground;
private final Object[] mStartForegroundArgs = new Object[2];
private final Object[] mStopForegroundArgs = new Object[1];
private Notification notification;
private Settings settings;
private HashMap<Integer, PendingIntent> alarmIntents;
private HashMap<Integer, ReconnectReceiver> alarmReceivers;
private final Object alarmIntentsLock;
/**
* Create new service
*/
public IRCService()
{
super();
this.connections = new HashMap<Integer, IRCConnection>();
this.binder = new IRCBinder(this);
this.connectedServerTitles = new ArrayList<String>();
this.mentions = new LinkedHashMap<String, Conversation>();
this.alarmIntents = new HashMap<Integer, PendingIntent>();
this.alarmReceivers = new HashMap<Integer, ReconnectReceiver>();
this.alarmIntentsLock = new Object();
}
/**
* On create
*/
@Override
public void onCreate()
{
super.onCreate();
settings = new Settings(getBaseContext());
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
try {
mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature);
mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature);
} catch (NoSuchMethodException e) {
// Running on an older platform.
mStartForeground = mStopForeground = null;
}
// Broadcast changed server list
sendBroadcast(new Intent(Broadcast.SERVER_UPDATE));
}
/**
* Get Settings object
*
* @return the settings helper object
*/
public Settings getSettings()
{
return settings;
}
/**
* On start (will be called on pre-2.0 platform. On 2.0 or later onStartCommand()
* will be called)
*/
@Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
handleCommand(intent);
}
/**
* On start command (Android >= 2.0)
*
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
if (intent != null) {
handleCommand(intent);
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
//return START_STICKY;
return 1;
}
/**
* Handle command
*
* @param intent
*/
private void handleCommand(Intent intent)
{
if (ACTION_FOREGROUND.equals(intent.getAction())) {
if (foreground) {
return; // XXX: We are already in foreground...
}
foreground = true;
// Set the icon, scrolling text and timestamp
notification = new Notification(R.drawable.ic_notification, getText(R.string.notification_running), System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
Intent notifyIntent = new Intent(this, MainActivity.class);
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.app_name), getText(R.string.notification_not_connected), contentIntent);
startForegroundCompat(FOREGROUND_NOTIFICATION, notification);
} else if (ACTION_BACKGROUND.equals(intent.getAction()) && !foreground) {
stopForegroundCompat(FOREGROUND_NOTIFICATION);
} else if (ACTION_ACK_NEW_MENTIONS.equals(intent.getAction())) {
ackNewMentions(intent.getIntExtra(EXTRA_ACK_SERVERID, -1), intent.getStringExtra(EXTRA_ACK_CONVTITLE));
}
}
/**
* Update notification and vibrate and/or flash a LED light if needed
*
* @param text The ticker text to display
* @param contentText The text to display in the notification dropdown
* @param vibrate True if the device should vibrate, false otherwise
* @param sound True if the device should make sound, false otherwise
* @param light True if the device should flash a LED light, false otherwise
*/
private void updateNotification(String text, String contentText, boolean vibrate, boolean sound, boolean light)
{
if (foreground) {
notification = new Notification(R.drawable.ic_notification, text, System.currentTimeMillis());
Intent notifyIntent = new Intent(this, MainActivity.class);
notifyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notifyIntent, 0);
if (contentText == null) {
if (newMentions >= 1) {
StringBuilder sb = new StringBuilder();
for (Conversation conv : mentions.values()) {
sb.append(conv.getName() + " (" + conv.getNewMentions() + "), ");
}
contentText = getString(R.string.notification_mentions, sb.substring(0, sb.length()-2));
} else if (!connectedServerTitles.isEmpty()) {
StringBuilder sb = new StringBuilder();
for (String title : connectedServerTitles) {
sb.append(title + ", ");
}
contentText = getString(R.string.notification_connected, sb.substring(0, sb.length()-2));
} else {
contentText = getString(R.string.notification_not_connected);
}
}
notification.setLatestEventInfo(this, getText(R.string.app_name), contentText, contentIntent);
if (vibrate) {
notification.defaults |= Notification.DEFAULT_VIBRATE;
}
if (sound) {
notification.defaults |= Notification.DEFAULT_SOUND;
}
if (light) {
notification.ledARGB = NOTIFICATION_LED_COLOR;
notification.ledOnMS = NOTIFICATION_LED_ON_MS;
notification.ledOffMS = NOTIFICATION_LED_OFF_MS;
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
}
notification.number = newMentions;
notificationManager.notify(FOREGROUND_NOTIFICATION, notification);
}
}
/**
* Generates a string uniquely identifying a conversation.
*/
public String getConversationId(int serverId, String title) {
return "" + serverId + ":" + title;
}
/**
* Notify the service of a new mention (updates the status bar notification)
*
* @param conversation The conversation where the new mention occurred
* @param msg The text of the new message
* @param vibrate Whether the notification should include vibration
* @param sound Whether the notification should include sound
* @param light Whether the notification should include a flashing LED light
*/
public synchronized void addNewMention(int serverId, Conversation conversation, String msg, boolean vibrate, boolean sound, boolean light)
{
if (conversation == null) {
return;
}
conversation.addNewMention();
++newMentions;
String convId = getConversationId(serverId, conversation.getName());
if (!mentions.containsKey(convId)) {
mentions.put(convId, conversation);
}
if (newMentions == 1) {
updateNotification(msg, msg, vibrate, sound, light);
} else {
updateNotification(msg, null, vibrate, sound, light);
}
}
/**
* Notify the service that new mentions have been viewed (updates the status bar notification)
*
* @param convTitle The title of the conversation whose new mentions have been read
*/
public synchronized void ackNewMentions(int serverId, String convTitle)
{
if (convTitle == null) {
return;
}
Conversation conversation = mentions.remove(getConversationId(serverId, convTitle));
if (conversation == null) {
return;
}
newMentions -= conversation.getNewMentions();
conversation.clearNewMentions();
if (newMentions < 0) {
newMentions = 0;
}
updateNotification(null, null, false, false, false);
}
/**
* Notify the service of connection to a server (updates the status bar notification)
*
* @param title The title of the newly connected server
*/
public synchronized void notifyConnected(String title)
{
connectedServerTitles.add(title);
updateNotification(getString(R.string.notification_connected, title), null, false, false, false);
}
/**
* Notify the service of disconnection from a server (updates the status bar notification)
*
* @param title The title of the disconnected server
*/
public synchronized void notifyDisconnected(String title)
{
connectedServerTitles.remove(title);
updateNotification(getString(R.string.notification_disconnected, title), null, false, false, false);
}
/**
* This is a wrapper around the new startForeground method, using the older
* APIs if it is not available.
*/
private void startForegroundCompat(int id, Notification notification)
{
// If we have the new startForeground API, then use it.
if (mStartForeground != null) {
mStartForegroundArgs[0] = Integer.valueOf(id);
mStartForegroundArgs[1] = notification;
try {
mStartForeground.invoke(this, mStartForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
} catch (IllegalAccessException e) {
// Should not happen.
}
} else {
// Fall back on the old API.
try {
Method setForeground = getClass().getMethod("setForeground", mSetForegroudSignaure);
setForeground.invoke(this, new Object[] { true });
} catch (NoSuchMethodException exception) {
// Should not happen
} catch (InvocationTargetException e) {
// Should not happen.
} catch (IllegalAccessException e) {
// Should not happen.
}
notificationManager.notify(id, notification);
}
}
/**
* This is a wrapper around the new stopForeground method, using the older
* APIs if it is not available.
*/
public void stopForegroundCompat(int id)
{
foreground = false;
// If we have the new stopForeground API, then use it.
if (mStopForeground != null) {
mStopForegroundArgs[0] = Boolean.TRUE;
try {
mStopForeground.invoke(this, mStopForegroundArgs);
} catch (InvocationTargetException e) {
// Should not happen.
} catch (IllegalAccessException e) {
// Should not happen.
}
} else {
// Fall back on the old API. Note to cancel BEFORE changing the
// foreground state, since we could be killed at that point.
notificationManager.cancel(id);
try {
Method setForeground = getClass().getMethod("setForeground", mSetForegroudSignaure);
setForeground.invoke(this, new Object[] { true });
} catch (NoSuchMethodException exception) {
// Should not happen
} catch (InvocationTargetException e) {
// Should not happen.
} catch (IllegalAccessException e) {
// Should not happen.
}
}
}
/**
* Connect to the given server
*/
public void connect(final Server server)
{
final int serverId = server.getId();
final int reconnectInterval = settings.getReconnectInterval()*60000;
final IRCService service = this;
if (settings.isReconnectEnabled()) {
server.setMayReconnect(true);
}
new Thread("Connect thread for " + server.getTitle()) {
@Override
public void run() {
synchronized(alarmIntentsLock) {
alarmIntents.remove(serverId);
ReconnectReceiver lastReceiver = alarmReceivers.remove(serverId);
if (lastReceiver != null) {
unregisterReceiver(lastReceiver);
}
}
if (settings.isReconnectEnabled() && !server.mayReconnect()) {
return;
}
try {
IRCConnection connection = getConnection(serverId);
connection.setNickname(server.getIdentity().getNickname());
connection.setAliases(server.getIdentity().getAliases());
connection.setIdent(server.getIdentity().getIdent());
connection.setRealName(server.getIdentity().getRealName());
connection.setUseSSL(server.useSSL());
if (server.getCharset() != null) {
connection.setEncoding(server.getCharset());
}
if (server.getAuthentication().hasSaslCredentials()) {
connection.setSaslCredentials(
server.getAuthentication().getSaslUsername(),
server.getAuthentication().getSaslPassword()
);
}
if (server.getPassword() != "") {
connection.connect(server.getHost(), server.getPort(), server.getPassword());
} else {
connection.connect(server.getHost(), server.getPort());
}
}
catch (Exception e) {
server.setStatus(Status.DISCONNECTED);
Intent sIntent = Broadcast.createServerIntent(Broadcast.SERVER_UPDATE, serverId);
sendBroadcast(sIntent);
IRCConnection connection = getConnection(serverId);
Message message;
if (e instanceof NickAlreadyInUseException) {
message = new Message(getString(R.string.nickname_in_use, connection.getNick()));
server.setMayReconnect(false);
} else if (e instanceof IrcException) {
message = new Message(getString(R.string.irc_login_error, server.getHost(), server.getPort()));
server.setMayReconnect(false);
} else {
message = new Message(getString(R.string.could_not_connect, server.getHost(), server.getPort()));
if (settings.isReconnectEnabled()) {
Intent rIntent = new Intent(Broadcast.SERVER_RECONNECT + serverId);
PendingIntent pendingRIntent = PendingIntent.getBroadcast(service, 0, rIntent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
ReconnectReceiver receiver = new ReconnectReceiver(service, server);
synchronized(alarmIntentsLock) {
alarmReceivers.put(serverId, receiver);
registerReceiver(receiver, new IntentFilter(Broadcast.SERVER_RECONNECT + serverId));
am.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + reconnectInterval, pendingRIntent);
alarmIntents.put(serverId, pendingRIntent);
}
}
}
message.setColor(Message.COLOR_RED);
message.setIcon(R.drawable.error);
server.getConversation(ServerInfo.DEFAULT_NAME).addMessage(message);
Intent cIntent = Broadcast.createConversationIntent(
Broadcast.CONVERSATION_MESSAGE,
serverId,
ServerInfo.DEFAULT_NAME
);
sendBroadcast(cIntent);
}
}
}.start();
}
/**
* Get connection for given server
*
* @param serverId
* @return
*/
public synchronized IRCConnection getConnection(int serverId)
{
IRCConnection connection = connections.get(serverId);
if (connection == null) {
connection = new IRCConnection(this, serverId);
connections.put(serverId, connection);
}
return connection;
}
/**
* Does the service keep a connection object for this server?
*
* @return true if there's a connection object, false otherwise
*/
public boolean hasConnection(int serverId)
{
return connections.containsKey(serverId);
}
/**
* Check status of service
*/
public void checkServiceStatus()
{
boolean shutDown = true;
ArrayList<Server> mServers = Yaaic.getInstance().getServersAsArrayList();
int mSize = mServers.size();
Server server;
for (int i = 0; i < mSize; i++) {
server = mServers.get(i);
if (server.isDisconnected() && !server.mayReconnect()) {
int serverId = server.getId();
synchronized(this) {
IRCConnection connection = connections.get(serverId);
if (connection != null) {
connection.dispose();
}
connections.remove(serverId);
}
synchronized(alarmIntentsLock) {
// XXX: alarmIntents can be null
PendingIntent pendingRIntent = alarmIntents.get(serverId);
if (pendingRIntent != null) {
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(pendingRIntent);
alarmIntents.remove(serverId);
}
ReconnectReceiver receiver = alarmReceivers.get(serverId);
if (receiver != null) {
unregisterReceiver(receiver);
alarmReceivers.remove(serverId);
}
}
} else {
shutDown = false;
}
}
if (shutDown) {
foreground = false;
stopForegroundCompat(R.string.app_name);
stopSelf();
}
}
/**
* On Destroy
*/
@Override
public void onDestroy()
{
// Make sure our notification is gone.
if (foreground) {
stopForegroundCompat(R.string.app_name);
}
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
synchronized(alarmIntentsLock) {
for (PendingIntent pendingRIntent : alarmIntents.values()) {
am.cancel(pendingRIntent);
}
for (ReconnectReceiver receiver : alarmReceivers.values()) {
unregisterReceiver(receiver);
}
alarmIntents.clear();
alarmIntents = null;
alarmReceivers.clear();
alarmReceivers = null;
}
}
/**
* On Activity binding to this service
*
* @param intent
* @return
*/
@Override
public IRCBinder onBind(Intent intent)
{
return binder;
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,29 +17,41 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.activity;
import org.yaaic.R;
import android.os.Bundle;
import android.preference.PreferenceActivity;
*/
package org.yaaic.listener;
/**
* Settings
* Listener for conversations
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class SettingsActivity extends PreferenceActivity
public interface ConversationListener
{
/**
* On create
*/
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
/**
* On new conversation message for given target
*
* @param target
*/
public void onConversationMessage(String target);
/**
* On new conversation created (for given target)
*
* @param target
*/
public void onNewConversation(String target);
/**
* On conversation removed (for given target)
*
* @param target
*/
public void onRemoveConversation(String target);
/**
* On topic changed (for given target)
*
* @param target
*/
public void onTopicChanged(String target);
}

View File

@ -0,0 +1,115 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.listener;
import android.content.Context;
import android.content.Intent;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.widget.TextView;
import org.yaaic.adapter.ConversationPagerAdapter;
import org.yaaic.irc.IRCService;
import org.yaaic.model.Channel;
import org.yaaic.model.Conversation;
import org.yaaic.model.Server;
/**
* Listener for conversation selections.
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class ConversationSelectedListener implements OnPageChangeListener
{
private final Context context;
private final Server server;
private final TextView titleView;
private final ConversationPagerAdapter adapter;
/**
* Create a new ConversationSelectedListener
*
* @param server
* @param titleView
*/
public ConversationSelectedListener(Context ctx, Server server, TextView titleView, ConversationPagerAdapter adapter)
{
this.context = ctx;
this.server = server;
this.titleView = titleView;
this.adapter = adapter;
}
/**
* On page has been selected.
*/
@Override
public void onPageSelected(int position)
{
Conversation conversation = adapter.getItem(position);
if (conversation != null && conversation.getType() != Conversation.TYPE_SERVER) {
StringBuilder sb = new StringBuilder();
sb.append(server.getTitle() + " - " + conversation.getName());
if (conversation.getType() == Conversation.TYPE_CHANNEL && !((Channel)conversation).getTopic().equals("")) {
sb.append(" - " + ((Channel)conversation).getTopic());
}
titleView.setText(sb.toString());
} else {
titleView.setText(server.getTitle());
}
// Remember selection
if (conversation != null) {
Conversation previousConversation = server.getConversation(server.getSelectedConversation());
if (previousConversation != null) {
previousConversation.setStatus(Conversation.STATUS_DEFAULT);
}
if (conversation.getNewMentions() > 0) {
Intent i = new Intent(context, IRCService.class);
i.setAction(IRCService.ACTION_ACK_NEW_MENTIONS);
i.putExtra(IRCService.EXTRA_ACK_SERVERID, server.getId());
i.putExtra(IRCService.EXTRA_ACK_CONVTITLE, conversation.getName());
context.startService(i);
}
conversation.setStatus(Conversation.STATUS_SELECTED);
server.setSelectedConversation(conversation.getName());
}
}
/**
* On scroll state of pager has been chanaged.
*/
@Override
public void onPageScrollStateChanged(int state)
{
}
/**
* On page has been scrolled.
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
{
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.listener;
import org.yaaic.activity.MessageActivity;
@ -36,38 +36,39 @@ import android.widget.AdapterView.OnItemClickListener;
*/
public class MessageClickListener implements OnItemClickListener
{
private static MessageClickListener instance;
/**
* Private constructor
*/
private MessageClickListener()
{
}
/**
* Get global instance of message click listener
*
* @return
*/
public static synchronized MessageClickListener getInstance()
{
if (instance == null) {
instance = new MessageClickListener();
}
return instance;
}
/**
* On message item clicked
*/
public void onItemClick(AdapterView<?> group, View view, int position, long id)
{
MessageListAdapter adapter = (MessageListAdapter) group.getAdapter();
Intent intent = new Intent(group.getContext(), MessageActivity.class);
intent.putExtra(Extra.MESSAGE, adapter.getItem(position).getText().toString());
group.getContext().startActivity(intent);
}
private static MessageClickListener instance;
/**
* Private constructor
*/
private MessageClickListener()
{
}
/**
* Get global instance of message click listener
*
* @return
*/
public static synchronized MessageClickListener getInstance()
{
if (instance == null) {
instance = new MessageClickListener();
}
return instance;
}
/**
* On message item clicked
*/
@Override
public void onItemClick(AdapterView<?> group, View view, int position, long id)
{
MessageListAdapter adapter = (MessageListAdapter) group.getAdapter();
Intent intent = new Intent(group.getContext(), MessageActivity.class);
intent.putExtra(Extra.MESSAGE, adapter.getItem(position).getText().toString());
group.getContext().startActivity(intent);
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,10 +17,18 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.listener;
/**
* Listener for changes regarding a server
*
* @author Sebastian Kaspari
*/
public interface ServerListener
{
public void onStatusUpdate();
/**
* On server status update (disconnected, connecting, connected)
*/
public void onStatusUpdate();
}

View File

@ -0,0 +1,79 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.menu;
import android.content.Context;
import android.view.MenuItem;
import android.view.View;
import android.widget.PopupMenu;
import org.yaaic.R;
import org.yaaic.adapter.ServersAdapter;
import org.yaaic.model.Server;
/**
* Popup menu for the server cards.
*/
public class ServerPopupMenu extends PopupMenu implements PopupMenu.OnMenuItemClickListener, View.OnClickListener {
private Server server;
private ServersAdapter.ClickListener listener;
public ServerPopupMenu(Context context, View anchor, ServersAdapter.ClickListener listener) {
super(context, anchor);
this.listener = listener;
getMenuInflater().inflate(R.menu.context_server, getMenu());
setOnMenuItemClickListener(this);
anchor.setOnClickListener(this);
}
public void updateServer(Server server) {
this.server = server;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.edit:
listener.onEditServer(server);
break;
case R.id.delete:
listener.onDeleteServer(server);
break;
case R.id.connect:
listener.onConnectToServer(server);
break;
case R.id.disconnect:
listener.onDisconnectFromServer(server);
break;
}
return true;
}
public void onClick(View v) {
show();
}
}

View File

@ -0,0 +1,125 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.model;
/**
* Authentication credentials for a server.
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class Authentication
{
private String saslUsername;
private String saslPassword;
private String nickservPassword;
/**
* Does this instance have credentials for Nickserv authentication?
*
* @return True if nickserv credentials are present, false otherwise.
*/
public boolean hasNickservCredentials()
{
return nickservPassword != null && nickservPassword.length() > 0;
}
/**
* Does this instance have credentials for SASL authentication?
*
* @return True if nickserv credentials are present, false otherwise.
*/
public boolean hasSaslCredentials()
{
return saslUsername != null && saslUsername.length() > 0;
}
/**
* Set the username for SASL authentication.
*
* @param saslUsername
*/
public void setSaslUsername(String saslUsername)
{
if (saslUsername == "") {
saslUsername = null;
}
this.saslUsername = saslUsername;
}
/**
* Set the password for SASL authentication.
*
* @param saslPassword
*/
public void setSaslPassword(String saslPassword)
{
if (saslPassword == "") {
saslPassword = null;
}
this.saslPassword = saslPassword;
}
/**
* Set the password for Nickserv authentication.
*
* @param nickservPassword
*/
public void setNickservPassword(String nickservPassword)
{
if (nickservPassword == "") {
nickservPassword = null;
}
this.nickservPassword = nickservPassword;
}
/**
* Get the username for SASL authentication.
*
* @return
*/
public String getSaslUsername()
{
return saslUsername;
}
/**
* Get the password for SASL authentication.
*
* @return
*/
public String getSaslPassword()
{
return saslPassword;
}
/**
* Get the password for Nickserv authentication.
*
* @return
*/
public String getNickservPassword()
{
return nickservPassword;
}
}

View File

@ -0,0 +1,73 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.model;
import android.content.Intent;
/**
* Constants and helpers for Broadcasts
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public abstract class Broadcast
{
public static final String SERVER_UPDATE = "org.yaaic.server.status";
public static final String SERVER_RECONNECT = "org.yaaic.server.reconnect.";
public static final String CONVERSATION_MESSAGE = "org.yaaic.conversation.message";
public static final String CONVERSATION_NEW = "org.yaaic.conversation.new";
public static final String CONVERSATION_REMOVE = "org.yaaic.conversation.remove";
public static final String CONVERSATION_TOPIC = "org.yaaic.conversation.topic";
/**
* Create an Intent for conversation broadcasting
*
* @param broadcastType The type of the broadcast, some constant of Broadcast.*
* @param serverId The id of the server
* @param conversationName The unique name of the conversation
* @return The created Intent
*/
public static Intent createConversationIntent(String broadcastType, int serverId, String conversationName)
{
Intent intent = new Intent(broadcastType);
intent.putExtra(Extra.SERVER, serverId);
intent.putExtra(Extra.CONVERSATION, conversationName);
return intent;
}
/**
* Create an Intent for server broadcasting
*
* @param broadcastType The typo of the broadcast, some constant of Broadcast.*
* @param serverId The id of the server
* @return The created Intent
*/
public static Intent createServerIntent(String broadcastType, int serverId)
{
Intent intent = new Intent(broadcastType);
intent.putExtra(Extra.SERVER, serverId);
return intent;
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.model;
/**
@ -27,45 +27,45 @@ package org.yaaic.model;
*/
public class Channel extends Conversation
{
private String topic;
private String topic;
/**
* Create a new channel object
*
* @param name of the channel
*/
public Channel(String name)
{
super(name);
this.topic = "";
}
/**
* Get the type of this conversation
*/
@Override
public int getType()
{
return Conversation.TYPE_CHANNEL;
}
/**
* Set the channel's topic
*
* @param topic The topic of the channel
*/
public void setTopic(String topic)
{
this.topic = topic;
}
/**
* Get the topic of the channel
*
* @return The channel's topic
*/
public String getTopic()
{
return topic;
}
/**
* Create a new channel object
*
* @param name of the channel
*/
public Channel(String name)
{
super(name);
this.topic = "";
}
/**
* Get the type of this conversation
*/
@Override
public int getType()
{
return Conversation.TYPE_CHANNEL;
}
/**
* Set the channel's topic
*
* @param topic The topic of the channel
*/
public void setTopic(String topic)
{
this.topic = topic;
}
/**
* Get the topic of the channel
*
* @return The channel's topic
*/
public String getTopic()
{
return topic;
}
}

View File

@ -0,0 +1,235 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.model;
import java.util.LinkedList;
/**
* Base class for conversations
*
* A conversation can be a channel, a query or server messages
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public abstract class Conversation
{
public static final int TYPE_CHANNEL = 1;
public static final int TYPE_QUERY = 2;
public static final int TYPE_SERVER = 3;
public static final int STATUS_DEFAULT = 1;
public static final int STATUS_SELECTED = 2;
public static final int STATUS_MESSAGE = 3;
public static final int STATUS_HIGHLIGHT = 4;
public static final int STATUS_MISC = 5; // join/part/quit
private static final int DEFAULT_HISTORY_SIZE = 30;
private final LinkedList<Message> buffer;
private final LinkedList<Message> history;
private final String name;
private int status = 1;
private int newMentions = 0;
private int historySize = DEFAULT_HISTORY_SIZE;
/**
* Get the type of conversation (channel, query, ..)
*
* @return See the constants: Conversation.TYPE_*
*/
public abstract int getType();
/**
* Create a new conversation with the given name
*
* @param name The name of the conversation (channel, user)
*/
public Conversation(String name)
{
this.buffer = new LinkedList<Message>();
this.history = new LinkedList<Message>();
this.name = name.toLowerCase();
}
/**
* Get name of the conversation (channel, user)
*/
public String getName()
{
return name;
}
/**
* Add a message to the channel
*/
public void addMessage(Message message)
{
buffer.add(0, message);
history.add(message);
if (history.size() > historySize) {
history.remove(0);
}
}
/**
* Get the history
*/
public LinkedList<Message> getHistory()
{
return history;
}
/**
* Get message of the history at the given position
*
* @param position
* @return The message at the given position
*/
public Message getHistoryMessage(int position)
{
return history.get(position);
}
/**
* Get last buffered message
*
* @return
*/
public Message pollBufferedMessage()
{
Message message = buffer.get(buffer.size() - 1);
buffer.remove(buffer.size() - 1);
return message;
}
/**
* Get the buffer
*
* @return
*/
public LinkedList<Message> getBuffer()
{
return buffer;
}
/**
* Does the channel have buffered messages?
*/
public boolean hasBufferedMessages()
{
return buffer.size() > 0;
}
/**
* Clear the message buffer
*/
public void clearBuffer()
{
buffer.clear();
}
/**
* Set status of conversation
*
* @param status
*/
public void setStatus(int status)
{
// Selected status can only be changed by deselecting
if (this.status == STATUS_SELECTED && status != STATUS_DEFAULT) {
return;
}
// Highlight status can only be changed by selecting
if (this.status == STATUS_HIGHLIGHT && status != STATUS_SELECTED) {
return;
}
// Misc cannot change any other than default
if (this.status != STATUS_DEFAULT && status == STATUS_MISC) {
return;
}
this.status = status;
}
/**
* Get status of conversation
*
* @return
*/
public int getStatus()
{
return status;
}
/**
* Increment the count of unread mentions in this conversation
*/
public void addNewMention()
{
++newMentions;
}
/**
* Mark all new mentions as unread
*/
public void clearNewMentions()
{
newMentions = 0;
}
/**
* Get the number of unread mentions in this conversation
*/
public int getNewMentions()
{
return newMentions;
}
/**
* Get this conversation's history size.
*
* @return The conversation's history size.
*/
public int getHistorySize()
{
return historySize;
}
/**
* Set this conversation's history size.
*
* @param size The new history size for this conversation.
*/
public void setHistorySize(int size)
{
if (size <= 0) {
return;
}
historySize = size;
if (history.size() > size) {
history.subList(size, history.size()).clear();
}
}
}

View File

@ -0,0 +1,47 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.model;
/**
* Helper class for constants used for bundle params (extras)
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class Extra
{
public static final String SERVER = "server";
public static final String CONVERSATION = "conversation";
public static final String USERS = "users";
public static final String ALIASES = "aliases";
public static final String CHANNELS = "channels";
public static final String COMMANDS = "commands";
public static final String MESSAGE = "message";
public static final String USER = "user";
public static final String ACTION = "action";
public static final String NICKSERV_PASSWORD = "nickserv_password";
public static final String SASL_USER = "sasl_user";
public static final String SASL_PASSWORD = "sasl_password";
public static final String CONNECT = "connect";
public static final String SERVER_ID = "serverId";
}

View File

@ -0,0 +1,120 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* An identity containing a nickname, an ident and a real name
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class Identity
{
private String nickname;
private final List<String> aliases = new ArrayList<String>();
private String ident;
private String realname;
/**
* Set the nickname of this identity
*
* @param nickname The nickname to be set
*/
public void setNickname(String nickname)
{
this.nickname = nickname;
}
/**
* Get the nickname of this identity
*
* @return The nickname
*/
public String getNickname()
{
return nickname;
}
/**
* Set a collection of aliases for this identity
*
* @param aliases
*/
public void setAliases(Collection<String> aliases)
{
this.aliases.clear();
this.aliases.addAll(aliases);
}
/**
* Get all aliases for this identity
*
* @return
*/
public List<String> getAliases()
{
return Collections.unmodifiableList(aliases);
}
/**
* Set the ident of this identity
*
* @param ident The ident to be set
*/
public void setIdent(String ident)
{
this.ident = ident;
}
/**
* Get the ident of this identity
*
* @return The identity
*/
public String getIdent()
{
return ident;
}
/**
* Set the real name of this identity
*
* @param realname The real name to be set
*/
public void setRealName(String realname)
{
this.realname = realname;
}
/**
* Get the real name of this identity
*
* @return The realname
*/
public String getRealName()
{
return realname;
}
}

View File

@ -0,0 +1,378 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
Yaaic 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.
Yaaic 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 Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.yaaic.model;
import java.util.Date;
import org.yaaic.utils.MircColors;
import org.yaaic.utils.Smilies;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
import android.text.util.Linkify;
import android.widget.TextView;
/**
* A channel or server message
*
* @author Sebastian Kaspari <sebastian@yaaic.org>
*/
public class Message
{
public static final int COLOR_GREEN = 0xFF458509;
public static final int COLOR_RED = 0xFFcc0000;
public static final int COLOR_BLUE = 0xFF729fcf;
public static final int COLOR_YELLOW = 0xFFbe9b01;
public static final int COLOR_GREY = 0xFFaaaaaa;
public static final int COLOR_DEFAULT = 0xFFeeeeee;
/* normal message, this is the default */
public static final int TYPE_MESSAGE = 0;
/* join, part or quit */
public static final int TYPE_MISC = 1;
/* Some are light versions because dark colors hardly readable on
* Yaaic's dark background */
public static final int[] colors = {
0xFFffffff, // White
0xFFffff00, // Yellow
0xFFff00ff, // Fuchsia
0xFFff0000, // Red
0xFFc0c0c0, // Silver
0xFF808080, // Gray
0xFF808000, // Olive
0xFFC040C0, // Light Purple
0xFFC04040, // Light Maroon
0xFF00ffff, // Agua
0xFF80ff80, // Light Lime
0xFF008080, // Teal
0xFF008000, // Green
0xFF8484FF, // Light Blue
0xFF6060D0, // Light Navy
0xFF000000, // Black
};
public static final int NO_ICON = -1;
public static final int NO_TYPE = -1;
public static final int NO_COLOR = -1;
private final String text;
private final String sender;
private SpannableString canvas;
private long timestamp;
private int color = NO_COLOR;
private int type = NO_ICON;
private int icon = NO_TYPE;
/**
* Create a new message without an icon defaulting to TYPE_MESSAGE
*
* @param text
*/
public Message(String text)
{
this(text, null, TYPE_MESSAGE);
}
/**
* Create a new message without an icon with a specific type
*
* @param text
* @param type Message type
*/
public Message(String text, int type)
{
this(text, null, type);
}
/**
* Create a new message sent by a user, without an icon,
* defaulting to TYPE_MESSAGE
*
* @param text
* @param sender
*/
public Message(String text, String sender)
{
this(text, sender, TYPE_MESSAGE);
}
/**
* Create a new message sent by a user without an icon
*
* @param text
* @param sender
* @param type Message type
*/
public Message(String text, String sender, int type)
{
this.text = text;
this.sender = sender;
this.timestamp = new Date().getTime();
this.type = type;
}
/**
* Set the message's icon
*/
public void setIcon(int icon)
{
this.icon = icon;
}
/**
* Get the message's icon
*
* @return
*/
public int getIcon()
{
return icon;
}
/**
* Get the text of this message
*
* @return
*/
public String getText()
{
return text;
}
/**
* Get the type of this message
*
* @return One of Message.TYPE_*
*/
public int getType()
{
return type;
}
/**
* Set the color of this message
*/
public void setColor(int color)
{
this.color = color;
}
/**
* Set the timestamp of the message
*
* @param timestamp
*/
public void setTimestamp(long timestamp)
{
this.timestamp = timestamp;
}
/**
* Associate a color with a sender name
*
* @return a color hexa
*/
private int getSenderColor()
{
/* It might be worth to use some hash table here */
if (sender == null) {
return COLOR_DEFAULT;
}
int color = 0;
for(int i = 0; i < sender.length(); i++){
color += sender.charAt(i);
}
/* we dont want color[colors.length-1] which is black */
color = color % (colors.length - 1);
return colors[color];
}
/**
* Render message as spannable string
*
* @return
*/
public SpannableString render(Context context)
{
Settings settings = new Settings(context);
if (canvas == null) {
String prefix = hasIcon() && settings.showIcons() ? " " : "";
String nick = hasSender() ? "<" + sender + "> " : "";
String timestamp = settings.showTimestamp() ? renderTimeStamp(settings.use24hFormat(), settings.includeSeconds()) : "";
canvas = new SpannableString(prefix + timestamp + nick);
SpannableString renderedText;
if (settings.showMircColors()) {
renderedText = MircColors.toSpannable(text);
} else {
renderedText = new SpannableString(
MircColors.removeStyleAndColors(text)
);
}
if (settings.showGraphicalSmilies()) {
renderedText = Smilies.toSpannable(renderedText, context);
}
canvas = new SpannableString(TextUtils.concat(canvas, renderedText));
if (hasSender()) {
int start = (prefix + timestamp).length() + 1;
int end = start + sender.length();
if (settings.showColorsNick()) {
canvas.setSpan(new ForegroundColorSpan(getSenderColor()), start, end , Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
if (hasIcon() && settings.showIcons()) {
Drawable drawable = context.getResources().getDrawable(icon);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
canvas.setSpan(new ImageSpan(drawable, ImageSpan.ALIGN_BOTTOM), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
if (hasColor() && settings.showColors()) {
// Only apply the foreground color to areas that don't already have a foreground color.
ForegroundColorSpan[] spans = canvas.getSpans(0, canvas.length(), ForegroundColorSpan.class);
int start = 0;
for (int i = 0; i < spans.length; i++) {
canvas.setSpan(new ForegroundColorSpan(color), start, canvas.getSpanStart(spans[i]), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
start = canvas.getSpanEnd(spans[i]);
}
canvas.setSpan(new ForegroundColorSpan(color), start, canvas.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return canvas;
}
/**
* Does this message have a sender?
*
* @return
*/
private boolean hasSender()
{
return sender != null;
}
/**
* Does this message have a color assigned?
*
* @return
*/
private boolean hasColor()
{
return color != NO_COLOR;
}
/**
* Does this message have an icon assigned?
*
* @return
*/
private boolean hasIcon()
{
return icon != NO_ICON;
}
/**
* Render message as text view
*
* @param context
* @return
*/
public TextView renderTextView(Context context)
{
TextView canvas = new TextView(context);
canvas.setAutoLinkMask(Linkify.ALL);
canvas.setLinksClickable(true);
canvas.setLinkTextColor(COLOR_BLUE);
canvas.setText(this.render(context));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
setupViewForHoneycombAndLater(canvas);
}
return canvas;
}
@TargetApi(11)
private void setupViewForHoneycombAndLater(TextView canvas) {
canvas.setTextIsSelectable(true);
}
/**
* Generate a timestamp
*
* @param use24hFormat
* @return
*/
public String renderTimeStamp(boolean use24hFormat, boolean includeSeconds)
{
Date date = new Date(timestamp);
int hours = date.getHours();
int minutes = date.getMinutes();
int seconds = date.getSeconds();
if (!use24hFormat) {
hours = Math.abs(12 - hours);
if (hours == 12) {
hours = 0;
}
}
if (includeSeconds) {
return String.format(
"[%02d:%02d:%02d]",
hours,
minutes,
seconds);
} else {
return String.format(
"[%02d:%02d]",
hours,
minutes);
}
}
}

View File

@ -1,7 +1,7 @@
/*
Yaaic - Yet Another Android IRC Client
Copyright 2009-2010 Sebastian Kaspari
Copyright 2009-2013 Sebastian Kaspari
This file is part of Yaaic.
@ -17,7 +17,7 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Yaaic. If not, see <http://www.gnu.org/licenses/>.
*/
*/
package org.yaaic.model;
/**
@ -27,21 +27,22 @@ package org.yaaic.model;
*/
public class Query extends Conversation
{
/**
* Create a new query
*
* @param name The user's nickname
*/
public Query(String name)
{
super(name);
}
/**
* Get the type of this conversation
*/
public int getType()
{
return Conversation.TYPE_QUERY;
}
/**
* Create a new query
*
* @param name The user's nickname
*/
public Query(String name)
{
super(name);
}
/**
* Get the type of this conversation
*/
@Override
public int getType()
{
return Conversation.TYPE_QUERY;
}
}

Some files were not shown because too many files have changed in this diff Show More