├── cordova ├── emulate.bat ├── appinfo.jar ├── BOOM.bat ├── log.bat ├── clean.bat ├── debug.bat ├── cordova.bat └── cordova.js ├── psd ├── icon.psd └── splash.psd ├── res ├── drawable │ ├── icon.png │ └── notification.png ├── drawable-hdpi │ ├── icon.png │ ├── ic_launcher.png │ └── notification.png ├── drawable-ldpi │ ├── icon.png │ ├── ic_launcher.png │ └── notification.png ├── drawable-mdpi │ ├── icon.png │ ├── ic_launcher.png │ └── notification.png ├── drawable-xhdpi │ ├── icon.png │ ├── ic_launcher.png │ └── notification.png ├── values │ └── strings.xml ├── layout │ └── main.xml └── xml │ └── config.xml ├── dist ├── lets-chat-001.apk └── lets-chat-002.apk ├── libs └── cordova-2.2.0.jar ├── assets └── www │ ├── media │ ├── img │ │ └── maze.png │ ├── js │ │ ├── vendor │ │ │ ├── uri.js │ │ │ ├── toe.js │ │ │ ├── statusbarnotification.js │ │ │ ├── store.js │ │ │ ├── moment.js │ │ │ ├── underscore.js │ │ │ ├── backbone.js │ │ │ └── ratchet.js │ │ ├── models.js │ │ ├── util │ │ │ └── message.js │ │ ├── client.js │ │ └── views.js │ ├── font │ │ ├── FontAwesome.otf │ │ ├── Pacifico-webfont.eot │ │ ├── Pacifico-webfont.ttf │ │ ├── Pacifico-webfont.woff │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ └── css │ │ ├── style.less │ │ ├── style │ │ ├── login.less │ │ ├── base.less │ │ └── chat.less │ │ ├── vendor │ │ └── font-awesome.less │ │ └── style.css │ ├── config.xml │ └── index.html ├── README.md ├── .settings └── org.eclipse.jdt.core.prefs ├── .classpath ├── project.properties ├── ant.properties ├── .gitignore ├── .project ├── src └── com │ ├── LetsChat │ └── LetsChat.java │ └── phonegap │ └── plugins │ └── statusBarNotification │ ├── StatusNotificationIntent.java │ └── StatusBarNotification.java └── AndroidManifest.xml /cordova/emulate.bat: -------------------------------------------------------------------------------- 1 | %~dp0\cordova.bat emulate 2 | -------------------------------------------------------------------------------- /psd/icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/psd/icon.psd -------------------------------------------------------------------------------- /psd/splash.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/psd/splash.psd -------------------------------------------------------------------------------- /cordova/appinfo.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/cordova/appinfo.jar -------------------------------------------------------------------------------- /res/drawable/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable/icon.png -------------------------------------------------------------------------------- /dist/lets-chat-001.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/dist/lets-chat-001.apk -------------------------------------------------------------------------------- /dist/lets-chat-002.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/dist/lets-chat-002.apk -------------------------------------------------------------------------------- /libs/cordova-2.2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/libs/cordova-2.2.0.jar -------------------------------------------------------------------------------- /res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /assets/www/media/img/maze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/img/maze.png -------------------------------------------------------------------------------- /res/drawable/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable/notification.png -------------------------------------------------------------------------------- /assets/www/media/js/vendor/uri.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/js/vendor/uri.js -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-hdpi/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-hdpi/notification.png -------------------------------------------------------------------------------- /res/drawable-ldpi/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-ldpi/notification.png -------------------------------------------------------------------------------- /res/drawable-mdpi/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-mdpi/notification.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/res/drawable-xhdpi/notification.png -------------------------------------------------------------------------------- /assets/www/media/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/font/FontAwesome.otf -------------------------------------------------------------------------------- /assets/www/media/font/Pacifico-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/font/Pacifico-webfont.eot -------------------------------------------------------------------------------- /assets/www/media/font/Pacifico-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/font/Pacifico-webfont.ttf -------------------------------------------------------------------------------- /assets/www/media/font/Pacifico-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/font/Pacifico-webfont.woff -------------------------------------------------------------------------------- /assets/www/media/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /assets/www/media/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /assets/www/media/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hhaidar/lets-chat-android/HEAD/assets/www/media/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Lets Chat 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Let's Chat Android Client 2 | ================= 3 | 4 | Writing an Android client for our little chat app... 5 | 6 | ![](http://i.imgur.com/xeLRVdp.jpg) 7 | -------------------------------------------------------------------------------- /assets/www/media/css/style.less: -------------------------------------------------------------------------------- 1 | @import 'vendor/ratchet.css'; 2 | @import 'vendor/font-awesome.less'; 3 | 4 | @import 'style/base.less'; 5 | @import 'style/login.less'; 6 | @import 'style/chat.less'; -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 3 | org.eclipse.jdt.core.compiler.compliance=1.6 4 | org.eclipse.jdt.core.compiler.source=1.6 5 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/layout/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /assets/www/media/js/models.js: -------------------------------------------------------------------------------- 1 | var UserModel = Backbone.Model.extend({}); 2 | 3 | var UsersCollection = Backbone.Collection.extend({ 4 | model: UserModel 5 | }); 6 | 7 | var MessageModel = Backbone.Model.extend({}); 8 | 9 | var MessagesCollection = Backbone.Collection.extend({ 10 | model: MessageModel 11 | }); 12 | 13 | var RoomModel = Backbone.Model.extend({ 14 | initialize: function() { 15 | this.messages = new MessagesCollection(); 16 | this.users = new UsersCollection(); 17 | } 18 | }); 19 | 20 | var RoomsCollection = Backbone.Collection.extend({ 21 | model: RoomModel 22 | }); -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-16 15 | -------------------------------------------------------------------------------- /ant.properties: -------------------------------------------------------------------------------- 1 | # This file is used to override default values used by the Ant build system. 2 | # 3 | # This file must be checked into Version Control Systems, as it is 4 | # integral to the build system of your project. 5 | 6 | # This file is only used by the Ant script. 7 | 8 | # You can use this to override default values such as 9 | # 'source.dir' for the location of your java source folder and 10 | # 'out.dir' for the location of your output folder. 11 | 12 | # You can also use it define how the release builds are signed by declaring 13 | # the following properties: 14 | # 'key.store' for the location of your keystore and 15 | # 'key.alias' for the name of the key to use. 16 | # The password will be asked during the build when you use the 'release' target. 17 | 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ANDROID / ECLIPSE 2 | 3 | # built application files 4 | *.apk 5 | *.ap_ 6 | 7 | # files for the dex VM 8 | *.dex 9 | 10 | # Java class files 11 | *.class 12 | 13 | # generated files - android project subfolder 14 | Android/bin/ 15 | Android/gen/ 16 | Android/assets/ 17 | 18 | # generated files 19 | bin/ 20 | gen/ 21 | 22 | # Local configuration file (sdk path, etc) 23 | local.properties 24 | 25 | # IOS / Xcode 26 | build/* 27 | *.pbxuser 28 | !default.pbxuser 29 | *.mode1v3 30 | !default.mode1v3 31 | *.mode2v3 32 | !default.mode2v3 33 | *.perspectivev3 34 | !default.perspectivev3 35 | *.xcworkspace 36 | !default.xcworkspace 37 | xcuserdata 38 | profile 39 | *.moved-aside 40 | IOS/www/ 41 | 42 | # OSX 43 | .DS_Store 44 | 45 | # Thumbnails 46 | ._* 47 | 48 | # Files that might appear on external disk 49 | .Spotlight-V100 50 | .Trashes -------------------------------------------------------------------------------- /cordova/BOOM.bat: -------------------------------------------------------------------------------- 1 | :: Licensed to the Apache Software Foundation (ASF) under one 2 | :: or more contributor license agreements. See the NOTICE file 3 | :: distributed with this work for additional information 4 | :: regarding copyright ownership. The ASF licenses this file 5 | :: to you under the Apache License, Version 2.0 (the 6 | :: "License"); you may not use this file except in compliance 7 | :: with the License. You may obtain a copy of the License at 8 | :: 9 | :: http://www.apache.org/licenses/LICENSE-2.0 10 | :: 11 | :: Unless required by applicable law or agreed to in writing, 12 | :: software distributed under the License is distributed on an 13 | :: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | :: KIND, either express or implied. See the License for the 15 | :: specific language governing permissions and limitations 16 | :: under the License. 17 | 18 | %~dp0\cordova.bat BOOM 19 | -------------------------------------------------------------------------------- /cordova/log.bat: -------------------------------------------------------------------------------- 1 | :: Licensed to the Apache Software Foundation (ASF) under one 2 | :: or more contributor license agreements. See the NOTICE file 3 | :: distributed with this work for additional information 4 | :: regarding copyright ownership. The ASF licenses this file 5 | :: to you under the Apache License, Version 2.0 (the 6 | :: "License"); you may not use this file except in compliance 7 | :: with the License. You may obtain a copy of the License at 8 | :: 9 | :: http://www.apache.org/licenses/LICENSE-2.0 10 | :: 11 | :: Unless required by applicable law or agreed to in writing, 12 | :: software distributed under the License is distributed on an 13 | :: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | :: KIND, either express or implied. See the License for the 15 | :: specific language governing permissions and limitations 16 | :: under the License. 17 | 18 | %~dp0\cordova.bat log 19 | -------------------------------------------------------------------------------- /cordova/clean.bat: -------------------------------------------------------------------------------- 1 | :: Licensed to the Apache Software Foundation (ASF) under one 2 | :: or more contributor license agreements. See the NOTICE file 3 | :: distributed with this work for additional information 4 | :: regarding copyright ownership. The ASF licenses this file 5 | :: to you under the Apache License, Version 2.0 (the 6 | :: "License"); you may not use this file except in compliance 7 | :: with the License. You may obtain a copy of the License at 8 | :: 9 | :: http://www.apache.org/licenses/LICENSE-2.0 10 | :: 11 | :: Unless required by applicable law or agreed to in writing, 12 | :: software distributed under the License is distributed on an 13 | :: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | :: KIND, either express or implied. See the License for the 15 | :: specific language governing permissions and limitations 16 | :: under the License. 17 | 18 | %~dp0\cordova.bat clean 19 | -------------------------------------------------------------------------------- /cordova/debug.bat: -------------------------------------------------------------------------------- 1 | :: Licensed to the Apache Software Foundation (ASF) under one 2 | :: or more contributor license agreements. See the NOTICE file 3 | :: distributed with this work for additional information 4 | :: regarding copyright ownership. The ASF licenses this file 5 | :: to you under the Apache License, Version 2.0 (the 6 | :: "License"); you may not use this file except in compliance 7 | :: with the License. You may obtain a copy of the License at 8 | :: 9 | :: http://www.apache.org/licenses/LICENSE-2.0 10 | :: 11 | :: Unless required by applicable law or agreed to in writing, 12 | :: software distributed under the License is distributed on an 13 | :: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | :: KIND, either express or implied. See the License for the 15 | :: specific language governing permissions and limitations 16 | :: under the License. 17 | 18 | %~dp0\cordova.bat debug 19 | -------------------------------------------------------------------------------- /assets/www/media/css/style/login.less: -------------------------------------------------------------------------------- 1 | .lcb-view-login { 2 | .content { 3 | background-image: url('../img/maze.png'); 4 | } 5 | button { 6 | width: 100%; 7 | } 8 | .response { 9 | background-color: #fcf8e3; 10 | color: #c09853; 11 | text-align: center; 12 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); 13 | padding: 10px; 14 | margin-bottom: 10px; 15 | border: 1px solid #fbeed5; 16 | .border-radius(4px); 17 | &:empty { 18 | display: none; 19 | } 20 | &.error { 21 | color: #b94a48; 22 | background-color: #f2dede; 23 | border-color: #eed3d7; 24 | } 25 | &.success { 26 | color: #468847; 27 | background-color: #dff0d8; 28 | border-color: #d6e9c6; 29 | } 30 | } 31 | .build { 32 | text-align: center; 33 | font-size: 12px; 34 | } 35 | } -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | LetsChat 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /assets/www/media/css/style/base.less: -------------------------------------------------------------------------------- 1 | body { 2 | width: 100%; 3 | font-size: 1em; 4 | } 5 | 6 | @font-face { 7 | font-family: 'Pacifico'; 8 | src: url('../font/Pacifico-webfont.eot'); 9 | src: url('../font/Pacifico-webfont.eot?#iefix') format('embedded-opentype'), 10 | url('../font/Pacifico-webfont.woff') format('woff'), 11 | url('../font/Pacifico-webfont.ttf') format('truetype'), 12 | url('../font/Pacifico-webfont.svg#PacificoRegular') format('svg'); 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | .view { 18 | display: none; 19 | } 20 | 21 | .view.current { 22 | display: block; 23 | } 24 | 25 | // Fixes android viewport issue 26 | @media (orientation:portrait) and (orientation:landscape) { 27 | .content, 28 | .bar-title { 29 | position:fixed; 30 | } 31 | } 32 | 33 | .bar-title .title { 34 | text-align: center; 35 | font-family: 'Pacifico'; 36 | } 37 | 38 | .count:empty { 39 | display: none; 40 | } -------------------------------------------------------------------------------- /cordova/cordova.bat: -------------------------------------------------------------------------------- 1 | :: Licensed to the Apache Software Foundation (ASF) under one 2 | :: or more contributor license agreements. See the NOTICE file 3 | :: distributed with this work for additional information 4 | :: regarding copyright ownership. The ASF licenses this file 5 | :: to you under the Apache License, Version 2.0 (the 6 | :: "License"); you may not use this file except in compliance 7 | :: with the License. You may obtain a copy of the License at 8 | :: 9 | :: http://www.apache.org/licenses/LICENSE-2.0 10 | :: 11 | :: Unless required by applicable law or agreed to in writing, 12 | :: software distributed under the License is distributed on an 13 | :: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | :: KIND, either express or implied. See the License for the 15 | :: specific language governing permissions and limitations 16 | :: under the License. 17 | 18 | @ECHO OFF 19 | IF NOT DEFINED JAVA_HOME GOTO MISSING 20 | FOR %%X in (java.exe ant.bat android.bat) do ( 21 | SET FOUND=%%~$PATH:X 22 | IF NOT DEFINED FOUND GOTO MISSING 23 | ) 24 | cscript %~dp0\cordova.js %* 25 | GOTO END 26 | :MISSING 27 | ECHO Missing one of the following: 28 | ECHO JDK: http://java.oracle.com 29 | ECHO Android SDK: http://developer.android.com 30 | ECHO Apache ant: http://ant.apache.org 31 | EXIT /B 1 32 | :END 33 | -------------------------------------------------------------------------------- /src/com/LetsChat/LetsChat.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | package com.LetsChat; 21 | 22 | import android.app.Activity; 23 | import android.os.Bundle; 24 | import org.apache.cordova.*; 25 | 26 | public class LetsChat extends DroidGap 27 | { 28 | @Override 29 | public void onCreate(Bundle savedInstanceState) 30 | { 31 | super.onCreate(savedInstanceState); 32 | super.loadUrl("file:///android_asset/www/index.html"); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/com/phonegap/plugins/statusBarNotification/StatusNotificationIntent.java: -------------------------------------------------------------------------------- 1 | // This class is used on all Androids below Honeycomb 2 | package com.phonegap.plugins.statusBarNotification; 3 | 4 | 5 | import android.app.Notification; 6 | import android.app.PendingIntent; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.pm.PackageManager; 10 | 11 | import com.LetsChat.R; 12 | 13 | public class StatusNotificationIntent { 14 | public static Notification buildNotification( Context context, CharSequence tag, CharSequence contentTitle, CharSequence contentText, int flag ) { 15 | int icon = R.drawable.notification; 16 | long when = System.currentTimeMillis(); 17 | Notification noti = new Notification(icon, contentTitle, when); 18 | noti.flags |= flag; 19 | 20 | PackageManager pm = context.getPackageManager(); 21 | Intent notificationIntent = pm.getLaunchIntentForPackage(context.getPackageName()); 22 | notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 23 | notificationIntent.putExtra("notificationTag", tag); 24 | 25 | PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0); 26 | noti.setLatestEventInfo(context, contentTitle, contentText, contentIntent); 27 | return noti; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /assets/www/media/js/util/message.js: -------------------------------------------------------------------------------- 1 | 2 | if (typeof window !== 'undefined' && typeof exports === 'undefined') { 3 | if (typeof window.utils !== 'object') window.utils = {}; 4 | } 5 | 6 | if (typeof exports !== 'undefined') { 7 | var _ = require('underscore'); 8 | } 9 | 10 | (function(exports) { 11 | // 12 | // Message Text Formatting 13 | // 14 | exports.format = function(text, plugins, mention) { 15 | // TODO: Fix these regexes 16 | var imagePattern = /((https?|ftp):\/\/[^\s\/$.?#].[^\s]*[.](jpe?g|png|gif)\s*$)/gi; 17 | var linkPattern = /((https?|ftp):\/\/[^\s\/$.?#].[^\s]*[^.])/gi; 18 | if (text.match(imagePattern)) { 19 | text = text.replace(imagePattern, '$1'); 20 | } else { 21 | text = text.replace(linkPattern, '$1'); 22 | } 23 | if (plugins) { 24 | // emotes 25 | _.each(plugins.emotes, function(emote, keyword) { 26 | var image = '' + encodeURI(keyword) + ''; 27 | text = text.replace(new RegExp('\\B' + keyword + '\\b', 'g'), image); 28 | }); 29 | // replacements 30 | _.each(plugins.replacements, function(replacement) { 31 | text = text.replace(new RegExp(replacement.regex, 'g'), replacement.template); 32 | }); 33 | } 34 | if (mention) { 35 | text = text.replace(new RegExp('(\\@' + mention + '\\b)', 'ig'), '$1') 36 | } 37 | return text; 38 | } 39 | })(typeof exports === 'undefined' ? window.utils.message = {} : exports); -------------------------------------------------------------------------------- /assets/www/media/css/style/chat.less: -------------------------------------------------------------------------------- 1 | .room-item { 2 | &:active { 3 | background: red; 4 | color: #fff; 5 | } 6 | } 7 | 8 | .messages { 9 | word-wrap: break-word; 10 | position: fixed; 11 | top: 44px; 12 | right: 0; 13 | bottom: 44px; 14 | left: 0; 15 | overflow: auto; 16 | padding: 0; 17 | margin: 0; 18 | } 19 | 20 | .message { 21 | background: #f2f2f2; 22 | border-bottom: 1px #eee solid; 23 | position: relative; 24 | .top { 25 | margin-left: 2px; 26 | } 27 | .name { 28 | font-weight: bold; 29 | color: #aaa; 30 | } 31 | .time { 32 | color: #bbb; 33 | } 34 | .avatar { 35 | width: 51px; 36 | height: 51px; 37 | margin-top: -1px; 38 | position: absolute; 39 | } 40 | .meta { 41 | background: #fff; 42 | min-height: 44px; 43 | padding: 3px 5px; 44 | margin-left: 51px; 45 | } 46 | .mention { 47 | font-weight: bold; 48 | color: #f22472; 49 | } 50 | .fragments { 51 | padding: 2px; 52 | } 53 | .fragment { 54 | padding: 2px; 55 | } 56 | .text { 57 | img { 58 | max-width: 100%; 59 | } 60 | } 61 | &.own { 62 | .avatar { 63 | right: 0; 64 | } 65 | .meta { 66 | text-align: right; 67 | margin-left: auto; 68 | margin-right: 51px; 69 | } 70 | } 71 | } 72 | 73 | .entry { 74 | padding: 0; 75 | box-shadow: 0 0 15px #bbb; 76 | display: -webkit-box; 77 | display: box; 78 | -webkit-box-orient: horizontal; 79 | box-orient: horizontal; 80 | &, input, button { 81 | display: -webkit-box; 82 | display: box; 83 | } 84 | input { 85 | width: auto; 86 | border: none; 87 | -webkit-box-shadow: none; 88 | box-shadow: none; 89 | -webkit-box-flex: 1; 90 | box-flex: 1; 91 | } 92 | .button { 93 | height: 100%; 94 | line-height: 30px; 95 | font-size: 22px; 96 | border-top: none; 97 | border-right: none; 98 | border-left-color: #ddd; 99 | border-radius: 0; 100 | -webkit-border-radius: 0; 101 | i { 102 | vertical-align: middle; 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /assets/www/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /res/xml/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 30 | 45 | 46 | 47 | 48 | 49 | 52 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /assets/www/media/js/vendor/toe.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * toe.js 3 | * version 2.0.0 4 | * author: Damien Antipa 5 | * https://github.com/dantipa/toe.js 6 | */ 7 | (function(t){var n={Event:function(n){var e={timestamp:(new Date).getTime(),target:n.target,point:[]},a=n.changedTouches||n.originalEvent.changedTouches||n.touches||n.originalEvent.touches;return t.each(a,function(t,n){e.point.push({x:n.pageX,y:n.pageY})}),e},State:function(t){var n=t.point[0];return{start:t,move:[],end:null,pageX:n.x,pageY:n.y}},track:function(e){var a,o=function(t){var o=n.Event(t);a=n.State(o),e.touchstart(t,a,o)},i=function(t){var o=n.Event(t);a.move.push(o),e.touchmove(t,a,o)},r=function(t){var o=n.Event(t);a.end=o,e.touchend(t,a,o)};return e.setup=function(n){t(this).on("touchstart",n,o).on("touchmove",n,i).on("touchend touchcancel",n,r)},e.teardown=function(){t(this).off("touchstart",o).off("touchmove",i).off("touchend touchcancel",r)},e},calc:{getDuration:function(t,n){return n.timestamp-t.timestamp},getDistance:function(t,n){return Math.sqrt(Math.pow(n.x-t.x,2)+Math.pow(n.y-t.y,2))},getAngle:function(t,n){return 180*Math.atan2(n.y-t.y,n.x-t.x)/Math.PI},getDirection:function(t){return-45>t&&t>-135?"top":t>=-45&&45>=t?"right":t>=45&&135>t?"down":t>=135||-135>=t?"left":"unknown"},getScale:function(t,n){var e=t.point,a=n.point;return 2===e.length&&2===a.length?(Math.sqrt(Math.pow(a[0].x-a[1].x,2)+Math.pow(a[0].y-a[1].y,2))/Math.sqrt(Math.pow(e[0].x-e[1].x,2)+Math.pow(e[0].y-e[1].y,2))).toFixed(2):0},getRotation:function(t,n){var e=t.point,a=n.point;return 2===e.length&&2===a.length?(180*Math.atan2(a[0].y-a[1].y,a[0].x-a[1].x)/Math.PI-180*Math.atan2(e[0].y-e[1].y,e[0].x-e[1].x)/Math.PI).toFixed(2):0}}};t.toe=n})(jQuery,this),function(t,n){t.event.special.swipe=function(){var e={distance:40,duration:300,direction:"all",finger:1};return n.track({touchstart:function(t,n){n.finger=n.start.point.length},touchmove:function(t,n,e){n.finger=e.point.length>n.finger?e.point.length:n.finger},touchend:function(a,o,i){var r,c,u=t.extend(e,a.data);r=n.calc.getDuration(o.start,i),c=n.calc.getDistance(o.start.point[0],i.point[0]),u.duration>r&&c>u.distance&&(o.angle=n.calc.getAngle(o.start.point[0],i.point[0]),o.direction=n.calc.getDirection(o.angle),o.finger!==u.finger||"all"!==u.direction&&o.direction!==u.direction||t(a.target).trigger(t.Event("swipe",o)))}})}()}(jQuery,jQuery.toe,this),function(t,n){t.event.special.tap=function(){var e={distance:10,duration:300,finger:1};return n.track({touchstart:function(t,n,e){n.finger=e.point.length},touchmove:function(t,n,e){n.finger=e.point.length>n.finger?e.point.length:n.finger},touchend:function(a,o,i){var r,c,u=t.extend(e,a.data);r=n.calc.getDuration(o.start,i),c=n.calc.getDistance(o.start.point[0],i.point[0]),u.duration>r&&u.distance>c&&o.finger===u.finger&&t(a.target).trigger(t.Event("tap",o))}})}()}(jQuery,jQuery.toe,this),function(t,n){t.event.special.taphold=function(){var e,a,o={distance:20,duration:500,finger:1};return n.track({touchstart:function(n,i,r){var c=t.extend(o,n.data);a=!1,i.finger=r.point.length,clearTimeout(e),e=setTimeout(function(){a||i.finger===c.finger&&t(n.target).trigger(t.Event("taphold",i))},c.duration)},touchmove:function(e,i,r){var c,u=t.extend(o,e.data);i.finger=r.point.length>i.finger?r.point.length:i.finger,c=n.calc.getDistance(i.start.point[0],r.point[0]),c>u.distance&&(a=!0)},touchend:function(){a=!0,clearTimeout(e)}})}()}(jQuery,jQuery.toe,this),function(t,n){t.event.special.transform=function(){var e,a={scale:.1,rotation:15};return n.track({touchstart:function(){e=!1},touchmove:function(o,i,r){var c=t.extend(a,o.data);return 2!==r.point.length?(i.move.pop(),undefined):(2!==i.start.point.length&&2===r.point.length&&(i.start=t.extend({},r)),i.rotation=n.calc.getRotation(i.start,r),i.scale=n.calc.getScale(i.start,r),(Math.abs(1-i.scale)>c.scale||Math.abs(i.rotation)>c.rotation)&&(e||(t(o.target).trigger(t.Event("transformstart",i)),e=!0),t(o.target).trigger(t.Event("transform",i))),undefined)},touchend:function(a,o,i){e&&(e=!1,2!==i.point.length&&(o.end=t.extend({},o.move[o.move.length-1])),o.rotation=n.calc.getRotation(o.start,o.end),o.scale=n.calc.getScale(o.start,o.end),t(a.target).trigger(t.Event("transformend",o)))}})}()}(jQuery,jQuery.toe,this); -------------------------------------------------------------------------------- /cordova/cordova.js: -------------------------------------------------------------------------------- 1 | // Licensed to the Apache Software Foundation (ASF) under one 2 | // or more contributor license agreements. See the NOTICE file 3 | // distributed with this work for additional information 4 | // regarding copyright ownership. The ASF licenses this file 5 | // to you under the Apache License, Version 2.0 (the 6 | // "License"); you may not use this file except in compliance 7 | // with the License. You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, 12 | // software distributed under the License is distributed on an 13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | // KIND, either express or implied. See the License for the 15 | // specific language governing permissions and limitations 16 | // under the License. 17 | 18 | var ROOT = WScript.ScriptFullName.split('\\cordova\\cordova.js').join(''), 19 | shell=WScript.CreateObject("WScript.Shell"); 20 | 21 | function exec(command) { 22 | var oExec=shell.Exec(command); 23 | var output = new String(); 24 | while(oExec.Status == 0) { 25 | if(!oExec.StdOut.AtEndOfStream) { 26 | var line = oExec.StdOut.ReadLine(); 27 | // XXX: Change to verbose mode 28 | // WScript.StdOut.WriteLine(line); 29 | output += line; 30 | } 31 | WScript.sleep(100); 32 | } 33 | 34 | return output; 35 | } 36 | 37 | function emulator_running() { 38 | var local_devices = shell.Exec("%comspec% /c adb devices").StdOut.ReadAll(); 39 | if(local_devices.match(/emulator/)) { 40 | return true; 41 | } 42 | return false; 43 | } 44 | function emulate() { 45 | // don't run emulator if a device is plugged in or if emulator is already running 46 | if(emulator_running()) { 47 | WScript.Echo("Device or Emulator already running!"); 48 | return; 49 | } 50 | var oExec = shell.Exec("%comspec% /c android.bat list avd"); 51 | var avd_list = []; 52 | var avd_id = -10; 53 | while(!oExec.StdOut.AtEndOfStream) { 54 | var output = oExec.StdOut.ReadLine(); 55 | if(output.match(/Name: (.)*/)) { 56 | avd_list.push(output.replace(/ *Name:\s/, "")); 57 | } 58 | } 59 | // user has no AVDs 60 | if(avd_list.length == 0) { 61 | WScript.Echo("You don't have any Android Virtual Devices. Please create at least one AVD."); 62 | WScript.Echo("android"); 63 | WScript.Quit(1); 64 | } 65 | // user has only one AVD so we launch that one 66 | if(avd_list.length == 1) { 67 | 68 | shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\cache -avd "+avd_list[0]); 69 | } 70 | 71 | // user has more than one avd so we ask them to choose 72 | if(avd_list.length > 1) { 73 | while(!avd_list[avd_id]) { 74 | WScript.Echo("Choose from one of the following Android Virtual Devices [0 to "+(avd_list.length - 1)+"]:") 75 | for(i = 0, j = avd_list.length ; i < j ; i++) { 76 | WScript.Echo((i)+") "+avd_list[i]); 77 | } 78 | WScript.StdOut.Write("> "); 79 | avd_id = new Number(WScript.StdIn.ReadLine()); 80 | } 81 | 82 | shell.Run("emulator -cpu-delay 0 -no-boot-anim -cache %Temp%\\cache -avd "+avd_list[avd_id], 0, false); 83 | } 84 | } 85 | 86 | function clean() { 87 | exec("%comspec% /c ant.bat clean -f "+ROOT+"\\build.xml 2>&1"); 88 | } 89 | 90 | function debug() { 91 | if(emulator_running()) { 92 | exec("%comspec% /c ant.bat debug install -f "+ROOT+"\\build.xml 2>&1"); 93 | } else { 94 | exec("%comspec% /c ant.bat debug -f "+ROOT+"\\build.xml 2>&1"); 95 | WScript.Echo("##################################################################"); 96 | WScript.Echo("# Plug in your device or launch an emulator with cordova/emulate #"); 97 | WScript.Echo("##################################################################"); 98 | } 99 | } 100 | 101 | function log() { 102 | shell.Run("%comspec% /c adb logcat"); 103 | } 104 | 105 | function launch() { 106 | var launch_str=exec("%comspec% /c java -jar "+ROOT+"\\cordova\\appinfo.jar "+ROOT+"\\AndroidManifest.xml"); 107 | //WScript.Echo(launch_str); 108 | exec("%comspec% /c adb shell am start -n "+launch_str+" 2>&1"); 109 | } 110 | 111 | function BOOM() { 112 | clean(); 113 | debug(); 114 | launch(); 115 | } 116 | var args = WScript.Arguments; 117 | if(args.count() != 1) { 118 | WScript.StdErr.Write("An error has occured!\n"); 119 | WScript.Quit(1); 120 | } 121 | eval(args(0)+"()"); 122 | -------------------------------------------------------------------------------- /assets/www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Let's Chat 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 |
26 |
27 |

28 | 29 | Let's Chat 30 |

31 |
32 |
33 |
34 |
35 |
36 | 37 | 38 |
39 |
40 | 41 | 42 |
43 |
44 | 45 | 46 |
47 |
48 |
49 | 50 |
51 |
Build 002
52 |
53 |
54 |
55 |
56 |

57 | 58 | Rooms 59 |

60 |
61 |
62 |
    63 |
    64 |
    65 |
    66 | 67 | 76 | 92 | 104 | 109 | -------------------------------------------------------------------------------- /assets/www/media/js/vendor/statusbarnotification.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2011 Dmitry Savchenko 4 | * 5 | * Permission is hereby granted, free of charge, to any person 6 | * obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without 8 | * restriction, including without limitation the rights to use, 9 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following 12 | * conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | * OTHER DEALINGS IN THE SOFTWARE. 25 | * 26 | */ 27 | 28 | var cordovaRef = window.PhoneGap || window.Cordova || window.cordova; // old to new fallbacks 29 | 30 | /** 31 | * Flags to denote the Android Notification constants 32 | * Values are representation from Android Notification Flag bit vals 33 | */ 34 | 35 | function Flag() {} 36 | Flag.FLAG_AUTO_CANCEL="16"; 37 | Flag.FLAG_NO_CLEAR="32"; 38 | 39 | /** @deprecated Use the W3C standard window.Notification API instead. */ 40 | var NotificationMessenger = function() { } 41 | 42 | /** 43 | * @param title Title of the notification 44 | * @param body Body of the notification 45 | * @deprecated Use the W3C standard window.Notification API instead. 46 | */ 47 | NotificationMessenger.prototype.notify = function(title, body, flag) { 48 | if (window.Notification) { 49 | this.activeNotification = new window.Notification(title, { 50 | body: body, 51 | flag: flag 52 | }); 53 | } 54 | } 55 | 56 | /** 57 | * Clears the Notificaiton Bar 58 | * @deprecated Use the W3C standard window.Notification API instead. 59 | */ 60 | NotificationMessenger.prototype.clear = function() { 61 | if (this.activeNotification) { 62 | this.activeNotification.close(); 63 | this.activeNotification = undefined; 64 | } 65 | } 66 | 67 | if (!window.plugins) window.plugins = {} 68 | if (!window.plugins.statusBarNotification) window.plugins.statusBarNotification = new NotificationMessenger(); 69 | 70 | 71 | /* 72 | * The W3C standard API, window.Notification. See http://www.w3.org/TR/notifications/ 73 | * This API should be used for new applications instead of the old plugin API above. 74 | */ 75 | if (typeof window.Notification == 'undefined') { 76 | 77 | /** 78 | * Creates and shows a new notification. 79 | * @param title 80 | * @param options 81 | */ 82 | window.Notification = function(title, options) { 83 | options = options || {}; 84 | this.tag = options.tag || 'defaultTag'; 85 | 86 | // Add this notification to the global index by tag. 87 | window.Notification.active[this.tag] = this; 88 | 89 | // May be undefined. 90 | this.onclick = options.onclick; 91 | this.onerror = options.onerror; 92 | this.onshow = options.onshow; 93 | this.onclose = options.onclose; 94 | 95 | var content = options.body || ''; 96 | 97 | var flag = options.flag || ''; 98 | 99 | cordova.exec(function() { 100 | if (this.onshow) { 101 | this.onshow(); 102 | } 103 | }, function(error) { 104 | if (this.onerror) { 105 | this.onerror(error); 106 | } 107 | }, 'StatusBarNotification', 'notify', [this.tag, title, content, flag]); 108 | }; 109 | 110 | // Permission is always granted on Android. 111 | window.Notification.permission = 'granted'; 112 | 113 | window.Notification.requestPermission = function(callback) { 114 | callback('granted'); 115 | }; 116 | 117 | // Not part of the W3C API. Used by the native side to call onclick handlers. 118 | window.Notification.callOnclickByTag = function(tag) { 119 | console.log('callOnclickByTag'); 120 | var notification = window.Notification.active[tag]; 121 | if (notification && notification.onclick && typeof notification.onclick == 'function') { 122 | console.log('inside if'); 123 | notification.onclick(); 124 | } 125 | }; 126 | 127 | // A global map of notifications by tag, so their onclick callbacks can be called. 128 | window.Notification.active = {}; 129 | 130 | 131 | /** 132 | * Cancels a notification that has already been created and shown to the user. 133 | */ 134 | window.Notification.prototype.close = function() { 135 | cordova.exec(function() { 136 | if (this.onclose) { 137 | this.onclose(); 138 | } 139 | }, function(error) { 140 | if (this.onerror) { 141 | this.onerror(error); 142 | } 143 | }, 'StatusBarNotification', 'clear', [this.tag]); 144 | }; 145 | } 146 | 147 | // vim: tabstop=4:softtabstop=4:shiftwidth=4:expandtab 148 | -------------------------------------------------------------------------------- /src/com/phonegap/plugins/statusBarNotification/StatusBarNotification.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Copyright (C) 2011 Dmitry Savchenko 4 | * 5 | * Permission is hereby granted, free of charge, to any person 6 | * obtaining a copy of this software and associated documentation 7 | * files (the "Software"), to deal in the Software without 8 | * restriction, including without limitation the rights to use, 9 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the 11 | * Software is furnished to do so, subject to the following 12 | * conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be 15 | * included in all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 | * OTHER DEALINGS IN THE SOFTWARE. 25 | * 26 | */ 27 | 28 | package com.phonegap.plugins.statusBarNotification; 29 | 30 | import org.apache.cordova.api.CallbackContext; 31 | import org.apache.cordova.api.CordovaPlugin; 32 | import org.json.JSONArray; 33 | import org.json.JSONException; 34 | 35 | import android.app.Notification; 36 | import android.app.NotificationManager; 37 | import android.content.Context; 38 | import android.content.Intent; 39 | import android.util.Log; 40 | 41 | public class StatusBarNotification extends CordovaPlugin { 42 | // Action to execute 43 | public static final String NOTIFY = "notify"; 44 | public static final String CLEAR = "clear"; 45 | 46 | /** 47 | * Executes the request and returns PluginResult 48 | * 49 | * @param action Action to execute 50 | * @param data JSONArray of arguments to the plugin 51 | * @param callbackContext The callback context used when calling back into JavaScript. 52 | * 53 | * @return A PluginRequest object with a status 54 | * */ 55 | @Override 56 | public boolean execute(String action, JSONArray data, CallbackContext callbackContext) { 57 | boolean actionValid = true; 58 | if (NOTIFY.equals(action)) { 59 | try { 60 | String tag = data.getString(0); 61 | String title = data.getString(1); 62 | String body = data.getString(2); 63 | String flag = data.getString(3); 64 | Log.d("NotificationPlugin", "Notification: " + tag + ", " + title + ", " + body); 65 | int notificationFlag = getFlagValue(flag); 66 | showNotification(tag, title, body, notificationFlag); 67 | } catch (JSONException jsonEx) { 68 | Log.d("NotificationPlugin", "Got JSON Exception " 69 | + jsonEx.getMessage()); 70 | actionValid = false; 71 | } 72 | } else if (CLEAR.equals(action)){ 73 | try { 74 | String tag = data.getString(0); 75 | Log.d("NotificationPlugin", "Notification cancel: " + tag); 76 | clearNotification(tag); 77 | } catch (JSONException jsonEx) { 78 | Log.d("NotificationPlugin", "Got JSON Exception " + jsonEx.getMessage()); 79 | actionValid = false; 80 | } 81 | } else { 82 | actionValid = false; 83 | Log.d("NotificationPlugin", "Invalid action : "+action+" passed"); 84 | } 85 | return actionValid; 86 | } 87 | 88 | /** 89 | * Helper method that returns a flag value to be used for notification 90 | * by default it will return 16 representing FLAG_NO_CLEAR 91 | * 92 | * @param flag 93 | * @return int value of the flag 94 | */ 95 | private int getFlagValue(String flag) { 96 | int flagVal = Notification.FLAG_AUTO_CANCEL; 97 | 98 | // We trust the flag value as it comes from our JS constant. 99 | // This is also backwards compatible as it will be emtpy. 100 | if (!flag.isEmpty()){ 101 | flagVal = Integer.parseInt(flag); 102 | } 103 | 104 | return flagVal; 105 | } 106 | 107 | /** 108 | * Displays status bar notification 109 | * 110 | * @param tag Notification tag. 111 | * @param contentTitle Notification title 112 | * @param contentText Notification text 113 | * */ 114 | public void showNotification( CharSequence tag, CharSequence contentTitle, CharSequence contentText, int flag) { 115 | String ns = Context.NOTIFICATION_SERVICE; 116 | context = cordova.getActivity().getApplicationContext(); 117 | mNotificationManager = (NotificationManager) context.getSystemService(ns); 118 | 119 | Notification noti = StatusNotificationIntent.buildNotification(context, tag, contentTitle, contentText, flag); 120 | mNotificationManager.notify(tag.hashCode(), noti); 121 | } 122 | 123 | /** 124 | * Cancels a single notification by tag. 125 | * 126 | * @param tag Notification tag to cancel. 127 | */ 128 | public void clearNotification(String tag) { 129 | mNotificationManager.cancel(tag.hashCode()); 130 | } 131 | 132 | /** 133 | * Removes all Notifications from the status bar. 134 | */ 135 | public void clearAllNotifications() { 136 | mNotificationManager.cancelAll(); 137 | } 138 | 139 | /** 140 | * Called when a notification is clicked. 141 | * @param intent The new Intent passed from the notification. 142 | */ 143 | @Override 144 | public void onNewIntent(Intent intent) { 145 | // The incoming Intent may or may not have been for a notification. 146 | String tag = intent.getStringExtra("notificationTag"); 147 | if (tag != null) { 148 | this.webView.sendJavascript("window.Notification.callOnclickByTag('"+ tag + "')"); 149 | } 150 | } 151 | 152 | 153 | private NotificationManager mNotificationManager; 154 | private Context context; 155 | } 156 | -------------------------------------------------------------------------------- /assets/www/media/js/client.js: -------------------------------------------------------------------------------- 1 | function Client() {}; 2 | 3 | Client.prototype.init = function() { 4 | var client = this; 5 | this.state = {}; 6 | this.events = _.extend({}, Backbone.Events); 7 | this.data = { 8 | user: new UserModel, 9 | rooms: new RoomsCollection 10 | } 11 | this.view = new ClientView({ 12 | client: this 13 | }); 14 | this.listenGUI(); 15 | this.route(); 16 | }; 17 | 18 | Client.prototype.route = function() { 19 | var self = this; 20 | var Router = Backbone.Router.extend({ 21 | routes: { 22 | '!/rooms': 'rooms', 23 | '!/room/:id': 'room', 24 | '*path': 'login' 25 | }, 26 | login: function() { 27 | if (self.state.authenticated) { 28 | this.navigate('!/rooms'); 29 | return; 30 | } 31 | self.events.trigger('views:show', 'login'); 32 | }, 33 | rooms: function() { 34 | if (!self.state.authenticated) { 35 | this.navigate('!/', true); 36 | return; 37 | } 38 | self.events.trigger('views:show', 'room-list'); 39 | }, 40 | room: function(id) { 41 | if (!self.state.authenticated) { 42 | this.navigate('!/', true); 43 | return; 44 | } 45 | self.events.trigger('views:show', id); 46 | } 47 | }); 48 | this.router = new Router; 49 | Backbone.history.start(); 50 | }; 51 | 52 | Client.prototype.listenGUI = function() { 53 | var self = this; 54 | this.events.on('client:pause', function() { 55 | self.state.paused = true; 56 | }); 57 | this.events.on('client:resume', function() { 58 | self.state.paused = false; 59 | }); 60 | this.events.on('client:login', this.login, this); 61 | this.events.on('room:message:send', function(message) { 62 | self.socket.emit('room:messages:new', message); 63 | }); 64 | this.events.on('room:message:new', function(message) { 65 | if (!client.state.paused) { 66 | return; 67 | } 68 | if (message.text.match(new RegExp('\\@' + self.data.user.get('safeName') + '\\b', 'g'))) { 69 | console.log(message.text.match(new RegExp('\\@' + self.data.user.get('safeName') + '\\b', 'ig'))); 70 | window.plugins.statusBarNotification.notify('Mentioned by ' + message.name, message.text); 71 | } 72 | }) 73 | }; 74 | 75 | Client.prototype.listenSocket = function() { 76 | var self = this; 77 | if (this.state.listenSocket) { 78 | return; 79 | } 80 | this.socket.on('connect', function() { 81 | self.socket.emit('user:whoami'); 82 | self.socket.emit('rooms:get'); 83 | }); 84 | this.socket.on('user:whoami', function(profile) { 85 | self.data.user.set(profile); 86 | }); 87 | this.socket.on('user:update', function(profile) { 88 | }); 89 | this.socket.on('room:messages:new', function(data) { 90 | if ($.isArray(data)) { 91 | _.each(data, function(message) { 92 | var room = self.data.rooms.get(message.room); 93 | room.messages.add(message, { 94 | silent: true 95 | }); 96 | room.messages.trigger('addsoftly', message); 97 | }); 98 | } else { 99 | var room = self.data.rooms.get(data.room); 100 | room.messages.add(data); 101 | self.events.trigger('room:message:new', data); 102 | } 103 | }); 104 | this.socket.on('room:users:new', function(user) { 105 | }); 106 | this.socket.on('room:users:leave', function(user) { 107 | }); 108 | this.socket.on('room:remove', function(id) { 109 | }); 110 | this.socket.on('room:update', function(data) { 111 | }); 112 | this.socket.on('rooms:new', function(room) { 113 | self.data.rooms.add(room); 114 | self.socket.emit('room:join', room.id); 115 | self.socket.emit('room:messages:get', { 116 | room: room.id 117 | }); 118 | }); 119 | this.socket.on('rooms:remove', function(id) { 120 | self.data.rooms.remove(id); 121 | }); 122 | this.socket.on('rooms:users:new', function(user) { 123 | }); 124 | this.socket.on('rooms:users:leave', function(user) { 125 | }); 126 | this.state.listenSocket = true; 127 | }; 128 | 129 | Client.prototype.login = function(creds) { 130 | var self = this; 131 | store.set('config', { 132 | url: creds.url, 133 | username: creds.username 134 | }); 135 | try { 136 | var connectionURL = URI(creds.url).search({ 137 | username: creds.username, 138 | password: creds.password 139 | }); 140 | if (!connectionURL.is('url') || !connectionURL.is('absolute')) { 141 | throw 'Invalid URL'; 142 | } 143 | this.connect(connectionURL.toString(), true); 144 | this.socket.once('error', function(err) { 145 | self.state.authenticated = false; 146 | self.events.trigger('client:login:error', err || 'Connection failed'); 147 | }); 148 | this.socket.once('connect', function() { 149 | self.state.authenticated = true; 150 | self.connect(connectionURL.toString(), false); 151 | self.events.trigger('client:login:success'); 152 | self.router.navigate('!/rooms', true); 153 | }); 154 | } catch(e) { 155 | this.events.trigger('client:login:error', e); 156 | } 157 | }; 158 | 159 | Client.prototype.connect = function(url, once) { 160 | if (once) { 161 | this.disconnect(); 162 | this.socket = io.connect(url, { 163 | reconnect: true, 164 | 'force new connection': true 165 | }); 166 | this.socket.once('connect', function() { 167 | this.disconnect(); 168 | }) 169 | return; 170 | } 171 | this.socket = io.connect(url, { 172 | reconnect: true, 173 | 'force new connection': false 174 | }); 175 | this.listenSocket(); 176 | } 177 | 178 | Client.prototype.disconnect = function() { 179 | if (this.socket && this.socket.socket.connected) { 180 | this.socket.disconnect(); 181 | return true; 182 | } 183 | return false; 184 | }; 185 | 186 | $(function() { 187 | window.client = new Client; 188 | window.client.init(); 189 | }); -------------------------------------------------------------------------------- /assets/www/media/js/vendor/store.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010-2012 Marcus Westin 2 | * 3 | * Permission is hereby granted, free of charge, to any person obtaining a copy 4 | * of this software and associated documentation files (the "Software"), to deal 5 | * in the Software without restriction, including without limitation the rights 6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | * copies of the Software, and to permit persons to whom the Software is 8 | * furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in 11 | * all copies or substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | * THE SOFTWARE. 20 | */ 21 | 22 | ;(function(){ 23 | var store = {}, 24 | win = window, 25 | doc = win.document, 26 | localStorageName = 'localStorage', 27 | globalStorageName = 'globalStorage', 28 | namespace = '__storejs__', 29 | storage 30 | 31 | store.disabled = false 32 | store.set = function(key, value) {} 33 | store.get = function(key) {} 34 | store.remove = function(key) {} 35 | store.clear = function() {} 36 | store.transact = function(key, defaultVal, transactionFn) { 37 | var val = store.get(key) 38 | if (transactionFn == null) { 39 | transactionFn = defaultVal 40 | defaultVal = null 41 | } 42 | if (typeof val == 'undefined') { val = defaultVal || {} } 43 | transactionFn(val) 44 | store.set(key, val) 45 | } 46 | store.getAll = function() {} 47 | 48 | store.serialize = function(value) { 49 | return JSON.stringify(value) 50 | } 51 | store.deserialize = function(value) { 52 | if (typeof value != 'string') { return undefined } 53 | try { return JSON.parse(value) } 54 | catch(e) { return value || undefined } 55 | } 56 | 57 | // Functions to encapsulate questionable FireFox 3.6.13 behavior 58 | // when about.config::dom.storage.enabled === false 59 | // See https://github.com/marcuswestin/store.js/issues#issue/13 60 | function isLocalStorageNameSupported() { 61 | try { return (localStorageName in win && win[localStorageName]) } 62 | catch(err) { return false } 63 | } 64 | 65 | function isGlobalStorageNameSupported() { 66 | try { return (globalStorageName in win && win[globalStorageName] && win[globalStorageName][win.location.hostname]) } 67 | catch(err) { return false } 68 | } 69 | 70 | if (isLocalStorageNameSupported()) { 71 | storage = win[localStorageName] 72 | store.set = function(key, val) { 73 | if (val === undefined) { return store.remove(key) } 74 | storage.setItem(key, store.serialize(val)) 75 | return val 76 | } 77 | store.get = function(key) { return store.deserialize(storage.getItem(key)) } 78 | store.remove = function(key) { storage.removeItem(key) } 79 | store.clear = function() { storage.clear() } 80 | store.getAll = function() { 81 | var ret = {} 82 | for (var i=0; idocument.w=window