aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--subsonic-android/res/layout/chat.xml46
-rw-r--r--subsonic-android/res/layout/chat_item.xml47
-rw-r--r--subsonic-android/res/layout/chat_item_reverse.xml50
-rw-r--r--subsonic-android/res/values/attrs.xml2
-rw-r--r--subsonic-android/res/values/strings.xml3
-rw-r--r--subsonic-android/res/values/themes.xml6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java6
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/domain/ChatMessage.java51
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/domain/Share.java140
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/fragments/ChatFragment.java167
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java18
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/MusicService.java8
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java58
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/parser/ChatMessageParser.java67
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/service/parser/ShareParser.java77
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/util/Util.java12
-rw-r--r--subsonic-android/src/github/daneren2005/dsub/view/ChatAdapter.java100
17 files changed, 853 insertions, 5 deletions
diff --git a/subsonic-android/res/layout/chat.xml b/subsonic-android/res/layout/chat.xml
new file mode 100644
index 00000000..fdeb5b36
--- /dev/null
+++ b/subsonic-android/res/layout/chat.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+
+ <include layout="@layout/tab_progress" />
+
+ <ListView
+ android:id="@+id/chat_entries"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0"
+ android:textFilterEnabled="true" />
+
+ <LinearLayout
+ android:layout_height="4dip"
+ android:layout_width="fill_parent"
+ android:layout_marginTop="4dip"/>
+
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="bottom" >
+
+ <EditText
+ android:id="@+id/chat_edittext"
+ android:layout_width="0dip"
+ android:layout_height="40dip"
+ android:layout_weight="1"
+ android:autoLink="all"
+ android:hint="@string/chat.send_a_message"
+ android:inputType="textEmailAddress|textMultiLine"
+ android:linksClickable="true"
+ android:paddingBottom="10dip"
+ android:paddingTop="10dip" />
+
+ <ImageButton
+ android:id="@+id/chat_send"
+ android:layout_width="60dip"
+ android:layout_height="40dip"
+ android:src="?attr/chat_send" />
+
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/res/layout/chat_item.xml b/subsonic-android/res/layout/chat_item.xml
new file mode 100644
index 00000000..b44631d1
--- /dev/null
+++ b/subsonic-android/res/layout/chat_item.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/chat_username"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:text="User"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:textColorSecondary"/>
+
+ <LinearLayout
+ android:id="@+id/chat_message_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dip"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/chat_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:singleLine="true"
+ android:text="00:00"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@+id/chat_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"
+ android:autoLink="all"
+ android:linksClickable="true"
+ android:singleLine="false"
+ android:text="Message Text Goes Here"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/res/layout/chat_item_reverse.xml b/subsonic-android/res/layout/chat_item_reverse.xml
new file mode 100644
index 00000000..62695521
--- /dev/null
+++ b/subsonic-android/res/layout/chat_item_reverse.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" >
+
+ <TextView
+ android:id="@+id/chat_username"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="6dip"
+ android:gravity="right"
+ android:layout_gravity="right"
+ android:ellipsize="marquee"
+ android:singleLine="true"
+ android:text="User"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:textColorSecondary"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dip"
+ android:orientation="horizontal"
+ android:layout_gravity="right" >
+
+ <TextView
+ android:id="@+id/chat_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:singleLine="true"
+ android:gravity="right"
+ android:text="00:00"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@+id/chat_message"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="6dip"
+ android:layout_marginRight="6dip"
+ android:autoLink="all"
+ android:linksClickable="true"
+ android:singleLine="false"
+ android:gravity="right"
+ android:text="Chat message"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/subsonic-android/res/values/attrs.xml b/subsonic-android/res/values/attrs.xml
index e5d8984f..8f669cd2 100644
--- a/subsonic-android/res/values/attrs.xml
+++ b/subsonic-android/res/values/attrs.xml
@@ -7,4 +7,6 @@
<attr name="media_button_repeat_off" format="reference"/>
<attr name="media_button_start" format="reference"/>
<attr name="media_button_stop" format="reference"/>
+ <attr name="chat" format="reference"/>
+ <attr name="chat_send" format="reference" />
</resources>
diff --git a/subsonic-android/res/values/strings.xml b/subsonic-android/res/values/strings.xml
index 0ba2b5c0..30bf5230 100644
--- a/subsonic-android/res/values/strings.xml
+++ b/subsonic-android/res/values/strings.xml
@@ -28,6 +28,7 @@
<string name="button_bar.search">Search</string>
<string name="button_bar.playlists">Playlists</string>
<string name="button_bar.now_playing">Playing</string>
+ <string name="button_bar.chat">Chat</string>
<string name="main.welcome_title">Welcome!</string>
<string name="main.welcome_text">Welcome to DSub! The app is currently configured to use the Subsonic demo server. After you\'ve
@@ -319,6 +320,8 @@
<string name="changelog_ok_button">OK</string>
<string name="changelog_show_full">Moreā€¦</string>
+ <string name="chat.send_a_message">Send a message</string>
+
<string name="changelog_version_format" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">Version <xliff:g id="version_name">%s</xliff:g></string>
<plurals name="select_album_n_songs">
diff --git a/subsonic-android/res/values/themes.xml b/subsonic-android/res/values/themes.xml
index 1e31b312..e48c3edc 100644
--- a/subsonic-android/res/values/themes.xml
+++ b/subsonic-android/res/values/themes.xml
@@ -10,6 +10,8 @@
<item name="media_button_repeat_off">@drawable/media_repeat_off_light</item>
<item name="media_button_start">@drawable/media_start_light</item>
<item name="media_button_stop">@drawable/media_stop_light</item>
+ <item name="chat">@drawable/ic_menu_chat_light</item>
+ <item name="chat_send">@drawable/ic_menu_chat_send_light</item>
</style>
<style name="Theme.DSub.Dark" parent="Theme.Sherlock">
<item name="actionBarStyle">@style/Widget.DSub.ActionBarStyle.Dark</item>
@@ -23,6 +25,8 @@
<item name="media_button_repeat_off">@drawable/media_repeat_off</item>
<item name="media_button_start">@drawable/media_start</item>
<item name="media_button_stop">@drawable/media_stop</item>
+ <item name="chat">@drawable/ic_menu_chat_dark</item>
+ <item name="chat_send">@drawable/ic_menu_chat_send_dark</item>
</style>
<style name="Theme.DSub.Holo" parent="Theme.Sherlock">
<item name="actionBarStyle">@style/Widget.DSub.ActionBarStyle.Holo</item>
@@ -36,6 +40,8 @@
<item name="media_button_repeat_off">@drawable/media_repeat_off</item>
<item name="media_button_start">@drawable/media_start</item>
<item name="media_button_stop">@drawable/media_stop</item>
+ <item name="chat">@drawable/ic_menu_chat_dark</item>
+ <item name="chat_send">@drawable/ic_menu_chat_send_dark</item>
</style>
<style name="Theme.DSub.Light.Fullscreen" parent="Theme.DSub.Light">
diff --git a/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
index d0eb86ef..16036bf1 100644
--- a/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
+++ b/subsonic-android/src/github/daneren2005/dsub/activity/MainActivity.java
@@ -1,9 +1,6 @@
package github.daneren2005.dsub.activity;
import android.app.AlertDialog;
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
@@ -15,13 +12,13 @@ import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.view.Menu;
import android.support.v4.view.ViewPager;
import android.util.Log;
-import android.view.KeyEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.PlayerState;
+import github.daneren2005.dsub.fragments.ChatFragment;
import github.daneren2005.dsub.fragments.MainFragment;
import github.daneren2005.dsub.fragments.SelectArtistFragment;
import github.daneren2005.dsub.fragments.SelectPlaylistFragment;
@@ -155,6 +152,7 @@ public class MainActivity extends SubsonicActivity {
addTab("Home", MainFragment.class, null);
addTab("Library", SelectArtistFragment.class, null);
addTab("Playlists", SelectPlaylistFragment.class, null);
+ addTab("Chat", ChatFragment.class, null);
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/ChatMessage.java b/subsonic-android/src/github/daneren2005/dsub/domain/ChatMessage.java
new file mode 100644
index 00000000..471594e9
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/domain/ChatMessage.java
@@ -0,0 +1,51 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic 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.
+
+ Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2009 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.domain;
+
+import java.io.Serializable;
+
+public class ChatMessage implements Serializable {
+ private String username;
+ private Long time;
+ private String message;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public Long getTime() {
+ return time;
+ }
+
+ public void setTime(Long time) {
+ this.time = time;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/domain/Share.java b/subsonic-android/src/github/daneren2005/dsub/domain/Share.java
new file mode 100644
index 00000000..d19496f9
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/domain/Share.java
@@ -0,0 +1,140 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic 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.
+
+ Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2009 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.domain;
+
+import github.daneren2005.dsub.domain.MusicDirectory.Entry;
+import java.io.Serializable;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+public class Share implements Serializable {
+ private String id;
+ private String url;
+ private String description;
+ private String username;
+ private Date created;
+ private Date lastVisited;
+ private Date expires;
+ private Long visitCount;
+ private List<Entry> entries;
+
+ public Share() {
+ entries = new ArrayList<Entry>();
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(String created) {
+ if (created != null) {
+ try {
+ this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created);
+ } catch (ParseException e) {
+ this.created = null;
+ }
+ } else {
+ this.created = null;
+ }
+ }
+
+ public Date getLastVisited() {
+ return lastVisited;
+ }
+
+ public void setLastVisited(String lastVisited) {
+ if (lastVisited != null) {
+ try {
+ this.lastVisited = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(lastVisited);
+ } catch (ParseException e) {
+ this.lastVisited = null;
+ }
+ } else {
+ this.lastVisited = null;
+ }
+ }
+
+ public Date getExpires() {
+ return expires;
+ }
+
+ public void setExpires(String expires) {
+ if (expires != null) {
+ try {
+ this.expires = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(expires);
+ } catch (ParseException e) {
+ this.expires = null;
+ }
+ } else {
+ this.expires = null;
+ }
+ }
+
+ public Long getVisitCount() {
+ return visitCount;
+ }
+
+ public void setVisitCount(Long visitCount) {
+ this.visitCount = visitCount;
+ }
+
+ public List<Entry> getEntries() {
+ return this.entries;
+ }
+
+ public void addEntry(Entry entry) {
+ entries.add(entry);
+ }
+ }
diff --git a/subsonic-android/src/github/daneren2005/dsub/fragments/ChatFragment.java b/subsonic-android/src/github/daneren2005/dsub/fragments/ChatFragment.java
new file mode 100644
index 00000000..8fba2526
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/fragments/ChatFragment.java
@@ -0,0 +1,167 @@
+package github.daneren2005.dsub.fragments;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ListView;
+import android.widget.TextView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.ChatMessage;
+import github.daneren2005.dsub.service.MusicService;
+import github.daneren2005.dsub.service.MusicServiceFactory;
+import github.daneren2005.dsub.util.BackgroundTask;
+import github.daneren2005.dsub.util.TabBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.ChatAdapter;
+import com.actionbarsherlock.view.Menu;
+
+/**
+ * @author Joshua Bahnsen
+ */
+public class ChatFragment extends SubsonicFragment {
+ private ListView chatListView;
+ private EditText messageEditText;
+ private ImageButton sendButton;
+ private Long lastChatMessageTime = (long) 0;
+ private ArrayList<ChatMessage> messageList = new ArrayList<ChatMessage>();
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.chat, container, false);
+
+ messageEditText = (EditText) rootView.findViewById(R.id.chat_edittext);
+ sendButton = (ImageButton) rootView.findViewById(R.id.chat_send);
+
+ sendButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ sendMessage();
+ }
+ });
+
+ chatListView = (ListView) rootView.findViewById(R.id.chat_entries);
+
+ messageEditText.setImeActionLabel("Send", KeyEvent.KEYCODE_ENTER);
+ messageEditText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable editable) {
+ sendButton.setEnabled(!Util.isNullOrWhiteSpace(editable.toString()));
+ }
+ });
+
+ messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
+
+ @Override
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (actionId == EditorInfo.IME_ACTION_DONE || (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_DOWN)) {
+ sendMessage();
+ return true;
+ }
+
+ return false;
+ }
+ });
+
+ invalidated = true;
+ return rootView;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, com.actionbarsherlock.view.MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.empty, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void refresh(boolean refresh) {
+ load();
+ }
+
+ private synchronized void load() {
+ setTitle(R.string.button_bar_chat);
+ BackgroundTask<List<ChatMessage>> task = new TabBackgroundTask<List<ChatMessage>>(this) {
+ @Override
+ protected List<ChatMessage> doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ return musicService.getChatMessages(lastChatMessageTime, context, this);
+ }
+
+ @Override
+ protected void done(List<ChatMessage> result) {
+ if (result != null && !result.isEmpty()) {
+ // Reset lastChatMessageTime if we have a newer message
+ for (ChatMessage message : result) {
+ if (message.getTime() > lastChatMessageTime) {
+ lastChatMessageTime = message.getTime();
+ }
+ }
+
+ // Reverse results to show them on the bottom
+ Collections.reverse(result);
+ messageList.addAll(result);
+
+ ChatAdapter chatAdapter = new ChatAdapter(context, messageList);
+ chatListView.setAdapter(chatAdapter);
+ }
+ }
+ };
+
+ task.execute();
+ }
+
+ private void sendMessage() {
+ final String message = messageEditText.getText().toString();
+
+ if (!Util.isNullOrWhiteSpace(message)) {
+ messageEditText.setText("");
+
+ BackgroundTask<Void> task = new TabBackgroundTask<Void>(this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.addChatMessage(message, context, this);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ load();
+ }
+ };
+
+ task.execute();
+ }
+ }
+} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java
index 32807289..3eb4184f 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/CachedMusicService.java
@@ -25,15 +25,16 @@ import org.apache.http.HttpResponse;
import android.content.Context;
import android.graphics.Bitmap;
+import github.daneren2005.dsub.domain.ChatMessage;
import github.daneren2005.dsub.domain.Indexes;
import github.daneren2005.dsub.domain.JukeboxStatus;
import github.daneren2005.dsub.domain.Lyrics;
import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.MusicDirectory.Entry;
import github.daneren2005.dsub.domain.MusicFolder;
import github.daneren2005.dsub.domain.Playlist;
import github.daneren2005.dsub.domain.SearchCritera;
import github.daneren2005.dsub.domain.SearchResult;
+import github.daneren2005.dsub.domain.Share;
import github.daneren2005.dsub.domain.Version;
import github.daneren2005.dsub.util.CancellableTask;
import github.daneren2005.dsub.util.LRUCache;
@@ -259,6 +260,21 @@ public class CachedMusicService implements MusicService {
public void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception {
musicService.setStarred(id, starred, context, progressListener);
}
+
+ @Override
+ public List<Share> getShares(Context context, ProgressListener progressListener) throws Exception {
+ return musicService.getShares(context, progressListener);
+ }
+
+ @Override
+ public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception {
+ return musicService.getChatMessages(since, context, progressListener);
+ }
+
+ @Override
+ public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception {
+ musicService.addChatMessage(message, context, progressListener);
+ }
private void checkSettingsChanged(Context context) {
String newUrl = Util.getRestUrl(context, null);
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java
index de3046d7..88391e53 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/MusicService.java
@@ -24,6 +24,7 @@ import org.apache.http.HttpResponse;
import android.content.Context;
import android.graphics.Bitmap;
+import github.daneren2005.dsub.domain.ChatMessage;
import github.daneren2005.dsub.domain.Indexes;
import github.daneren2005.dsub.domain.JukeboxStatus;
import github.daneren2005.dsub.domain.Lyrics;
@@ -32,6 +33,7 @@ import github.daneren2005.dsub.domain.MusicFolder;
import github.daneren2005.dsub.domain.Playlist;
import github.daneren2005.dsub.domain.SearchCritera;
import github.daneren2005.dsub.domain.SearchResult;
+import github.daneren2005.dsub.domain.Share;
import github.daneren2005.dsub.domain.Version;
import github.daneren2005.dsub.util.CancellableTask;
import github.daneren2005.dsub.util.ProgressListener;
@@ -102,4 +104,10 @@ public interface MusicService {
JukeboxStatus setJukeboxGain(float gain, Context context, ProgressListener progressListener) throws Exception;
void setStarred(String id, boolean starred, Context context, ProgressListener progressListener) throws Exception;
+
+ List<Share> getShares(Context context, ProgressListener progressListener) throws Exception;
+
+ List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception;
+
+ void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception;
} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
index 24dcbabd..daa9291a 100644
--- a/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/subsonic-android/src/github/daneren2005/dsub/service/RESTMusicService.java
@@ -73,6 +73,7 @@ import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.*;
import github.daneren2005.dsub.domain.MusicDirectory.Entry;
import github.daneren2005.dsub.service.parser.AlbumListParser;
+import github.daneren2005.dsub.service.parser.ChatMessageParser;
import github.daneren2005.dsub.service.parser.ErrorParser;
import github.daneren2005.dsub.service.parser.IndexesParser;
import github.daneren2005.dsub.service.parser.JukeboxStatusParser;
@@ -85,6 +86,7 @@ import github.daneren2005.dsub.service.parser.PlaylistsParser;
import github.daneren2005.dsub.service.parser.RandomSongsParser;
import github.daneren2005.dsub.service.parser.SearchResult2Parser;
import github.daneren2005.dsub.service.parser.SearchResultParser;
+import github.daneren2005.dsub.service.parser.ShareParser;
import github.daneren2005.dsub.service.parser.StarredListParser;
import github.daneren2005.dsub.service.parser.VersionParser;
import github.daneren2005.dsub.service.ssl.SSLSocketFactory;
@@ -729,6 +731,62 @@ public class RESTMusicService implements MusicService {
Util.close(reader);
}
}
+
+ @Override
+ public List<Share> getShares(Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.6", "Shares not supported.");
+
+ Reader reader = getReader(context, progressListener, "getShares", null);
+ try {
+ return new ShareParser(context).parse(reader, progressListener);
+ } finally {
+ Util.close(reader);
+ }
+ }
+
+ @Override
+ public List<ChatMessage> getChatMessages(Long since, Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.2", "Chat not supported.");
+
+ HttpParams params = new BasicHttpParams();
+ HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS);
+
+ List<String> parameterNames = new ArrayList<String>();
+ List<Object> parameterValues = new ArrayList<Object>();
+
+ parameterNames.add("since");
+ parameterValues.add(since);
+
+ Reader reader = getReader(context, progressListener, "getChatMessages", params, parameterNames, parameterValues);
+
+ try {
+ return new ChatMessageParser(context).parse(reader, progressListener);
+ } finally {
+ Util.close(reader);
+ }
+ }
+
+ @Override
+ public void addChatMessage(String message, Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.2", "Chat not supported.");
+
+ HttpParams params = new BasicHttpParams();
+ HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_RANDOM_SONGS);
+
+ List<String> parameterNames = new ArrayList<String>();
+ List<Object> parameterValues = new ArrayList<Object>();
+
+ parameterNames.add("message");
+ parameterValues.add(message);
+
+ Reader reader = getReader(context, progressListener, "addChatMessage", params, parameterNames, parameterValues);
+
+ try {
+ new ErrorParser(context).parse(reader);
+ } finally {
+ Util.close(reader);
+ }
+ }
private Reader getReader(Context context, ProgressListener progressListener, String method, HttpParams requestParams) throws Exception {
return getReader(context, progressListener, method, requestParams, Collections.<String>emptyList(), Collections.emptyList());
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/ChatMessageParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/ChatMessageParser.java
new file mode 100644
index 00000000..1425a734
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/ChatMessageParser.java
@@ -0,0 +1,67 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic 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.
+
+ Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2009 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.service.parser;
+
+import android.content.Context;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.ChatMessage;
+import github.daneren2005.dsub.util.ProgressListener;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Joshua Bahnsen
+ */
+public class ChatMessageParser extends AbstractParser {
+
+ public ChatMessageParser(Context context) {
+ super(context);
+ }
+
+ public List<ChatMessage> parse(Reader reader, ProgressListener progressListener) throws Exception {
+ updateProgress(progressListener, R.string.parser_reading);
+ init(reader);
+ List<ChatMessage> result = new ArrayList<ChatMessage>();
+ int eventType;
+
+ do {
+ eventType = nextParseEvent();
+ if (eventType == XmlPullParser.START_TAG) {
+ String name = getElementName();
+ if ("chatMessage".equals(name)) {
+ ChatMessage chatMessage = new ChatMessage();
+ chatMessage.setUsername(get("username"));
+ chatMessage.setTime(getLong("time"));
+ chatMessage.setMessage(get("message"));
+ result.add(chatMessage);
+ } else if ("error".equals(name)) {
+ handleError();
+ }
+ }
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ validate();
+ updateProgress(progressListener, R.string.parser_reading_done);
+
+ return result;
+ }
+}
diff --git a/subsonic-android/src/github/daneren2005/dsub/service/parser/ShareParser.java b/subsonic-android/src/github/daneren2005/dsub/service/parser/ShareParser.java
new file mode 100644
index 00000000..c317e799
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/service/parser/ShareParser.java
@@ -0,0 +1,77 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic 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.
+
+ Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2009 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.service.parser;
+
+import android.content.Context;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.Share;
+import github.daneren2005.dsub.util.ProgressListener;
+import org.xmlpull.v1.XmlPullParser;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Joshua Bahnsen
+ */
+public class ShareParser extends MusicDirectoryEntryParser {
+
+ public ShareParser(Context context) {
+ super(context);
+ }
+
+ public List<Share> parse(Reader reader, ProgressListener progressListener) throws Exception {
+
+ updateProgress(progressListener, R.string.parser_reading);
+ init(reader);
+
+ List<Share> dir = new ArrayList<Share>();
+ Share share = null;
+ int eventType;
+
+ do {
+ eventType = nextParseEvent();
+
+ if (eventType == XmlPullParser.START_TAG) {
+ String name = getElementName();
+
+ if ("share".equals(name)) {
+ share = new Share();
+ share.setCreated(get("created"));
+ share.setDescription(get("description"));
+ share.setExpires(get("expires"));
+ share.setId(get("id"));
+ share.setLastVisited(get("lastVisited"));
+ share.setUrl(get("url"));
+ share.setUsername(get("username"));
+ share.setVisitCount(getLong("visitCount"));
+ } else if ("entry".equals(name)) {
+ share.addEntry(parseEntry(null));
+ } else if ("error".equals(name)) {
+ handleError();
+ }
+ }
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ validate();
+ updateProgress(progressListener, R.string.parser_reading_done);
+
+ return dir;
+ }
+} \ No newline at end of file
diff --git a/subsonic-android/src/github/daneren2005/dsub/util/Util.java b/subsonic-android/src/github/daneren2005/dsub/util/Util.java
index a7c1b720..93acfcb8 100644
--- a/subsonic-android/src/github/daneren2005/dsub/util/Util.java
+++ b/subsonic-android/src/github/daneren2005/dsub/util/Util.java
@@ -209,6 +209,14 @@ public final class Util {
SharedPreferences prefs = getPreferences(context);
return prefs.getString(Constants.PREFERENCES_KEY_SERVER_NAME + instance, null);
}
+
+ public static String getUserName(Context context, int instance) {
+ if (instance == 0) {
+ return context.getResources().getString(R.string.main_offline);
+ }
+ SharedPreferences prefs = getPreferences(context);
+ return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null);
+ }
public static void setServerRestVersion(Context context, Version version) {
SERVER_REST_VERSIONS.put(getActiveServer(context), version);
@@ -634,6 +642,10 @@ public final class Util {
throw new RuntimeException(x.getMessage(), x);
}
}
+
+ public static boolean isNullOrWhiteSpace(String string) {
+ return string == null || string.isEmpty() || string.trim().isEmpty();
+ }
public static boolean isNetworkConnected(Context context) {
ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
diff --git a/subsonic-android/src/github/daneren2005/dsub/view/ChatAdapter.java b/subsonic-android/src/github/daneren2005/dsub/view/ChatAdapter.java
new file mode 100644
index 00000000..518f81ef
--- /dev/null
+++ b/subsonic-android/src/github/daneren2005/dsub/view/ChatAdapter.java
@@ -0,0 +1,100 @@
+package github.daneren2005.dsub.view;
+
+import android.text.method.LinkMovementMethod;
+import android.text.util.Linkify;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.activity.SubsonicActivity;
+import github.daneren2005.dsub.domain.ChatMessage;
+import github.daneren2005.dsub.util.Util;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.regex.Pattern;
+
+public class ChatAdapter extends ArrayAdapter<ChatMessage> {
+
+ private final SubsonicActivity activity;
+ private ArrayList<ChatMessage> messages;
+
+ private static final String phoneRegex = "1?\\W*([2-9][0-8][0-9])\\W*([2-9][0-9]{2})\\W*([0-9]{4})"; //you can just place your support phone here
+ private static final Pattern phoneMatcher = Pattern.compile(phoneRegex);
+
+ public ChatAdapter(SubsonicActivity activity, ArrayList<ChatMessage> messages) {
+ super(activity, R.layout.chat_item, messages);
+ this.activity = activity;
+ this.messages = messages;
+ }
+
+ @Override
+ public int getCount() {
+ return messages.size();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ChatMessage message = this.getItem(position);
+
+ ViewHolder holder;
+ int layout;
+
+ String messageUser = message.getUsername();
+ Date messageTime = new java.util.Date(message.getTime());
+ String messageText = message.getMessage();
+
+ String me = Util.getUserName(activity, Util.getActiveServer(activity));
+
+ if (messageUser.equals(me)) {
+ layout = R.layout.chat_item_reverse;
+ } else {
+ layout = R.layout.chat_item;
+ }
+
+ if (convertView == null)
+ {
+ holder = new ViewHolder();
+
+ convertView = LayoutInflater.from(activity).inflate(layout, parent, false);
+
+ TextView usernameView = (TextView) convertView.findViewById(R.id.chat_username);
+ TextView timeView = (TextView) convertView.findViewById(R.id.chat_time);
+ TextView messageView = (TextView) convertView.findViewById(R.id.chat_message);
+
+ messageView.setMovementMethod(LinkMovementMethod.getInstance());
+ Linkify.addLinks(messageView, Linkify.EMAIL_ADDRESSES);
+ Linkify.addLinks(messageView, Linkify.WEB_URLS);
+ Linkify.addLinks(messageView, phoneMatcher, "tel:");
+
+ holder.message = messageView;
+ holder.username = usernameView;
+ holder.time = timeView;
+
+ convertView.setTag(holder);
+ }
+ else
+ {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ DateFormat timeFormat = android.text.format.DateFormat.getTimeFormat(activity);
+ String messageTimeFormatted = String.format("[%s]", timeFormat.format(messageTime));
+
+ holder.username.setText(messageUser);
+ holder.message.setText(messageText);
+ holder.time.setText(messageTimeFormatted);
+
+ return convertView;
+ }
+
+ private static class ViewHolder
+ {
+ TextView message;
+ TextView username;
+ TextView time;
+ }
+}