From 14893daf30e01cd1d99bbcbb1d222450be853126 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Sat, 7 Jun 2014 13:12:45 -0700 Subject: #171 Add basic admin tab --- .../dsub/activity/SubsonicActivity.java | 11 +- .../dsub/activity/SubsonicFragmentActivity.java | 3 + src/github/daneren2005/dsub/domain/User.java | 161 +++++++++++++++++++++ .../daneren2005/dsub/fragments/AdminFragment.java | 64 ++++++++ .../dsub/service/CachedMusicService.java | 33 +++++ .../daneren2005/dsub/service/MusicService.java | 5 + .../dsub/service/OfflineMusicService.java | 15 +- .../daneren2005/dsub/service/RESTMusicService.java | 29 ++++ .../dsub/service/parser/UserParser.java | 73 ++++++++++ src/github/daneren2005/dsub/util/Constants.java | 1 + src/github/daneren2005/dsub/view/UserAdapter.java | 49 +++++++ src/github/daneren2005/dsub/view/UserView.java | 50 +++++++ 12 files changed, 489 insertions(+), 5 deletions(-) create mode 100644 src/github/daneren2005/dsub/domain/User.java create mode 100644 src/github/daneren2005/dsub/fragments/AdminFragment.java create mode 100644 src/github/daneren2005/dsub/service/parser/UserParser.java create mode 100644 src/github/daneren2005/dsub/view/UserAdapter.java create mode 100644 src/github/daneren2005/dsub/view/UserView.java (limited to 'src') diff --git a/src/github/daneren2005/dsub/activity/SubsonicActivity.java b/src/github/daneren2005/dsub/activity/SubsonicActivity.java index 646fa295..edec6b90 100644 --- a/src/github/daneren2005/dsub/activity/SubsonicActivity.java +++ b/src/github/daneren2005/dsub/activity/SubsonicActivity.java @@ -75,7 +75,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte private String[] drawerItemsDescriptions; private String[] drawerItems; private boolean drawerIdle = true; - private boolean[] enabledItems = {true, true, true, true}; + private boolean[] enabledItems = {true, true, true, true, true}; private boolean destroyed = false; private boolean finished = false; protected List backStack = new ArrayList(); @@ -386,8 +386,9 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte boolean bookmarksEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_BOOKMARKS_ENABLED, true) && !Util.isOffline(this); boolean sharedEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SHARED_ENABLED, true) && !Util.isOffline(this); boolean chatEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_CHAT_ENABLED, true) && !Util.isOffline(this); + boolean adminEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_ADMIN_ENABLED, true) && !Util.isOffline(this); - if(drawerItems == null || !enabledItems[0] == podcastsEnabled || !enabledItems[1] == bookmarksEnabled || !enabledItems[2] == sharedEnabled || !enabledItems[3] == chatEnabled) { + if(drawerItems == null || !enabledItems[0] == podcastsEnabled || !enabledItems[1] == bookmarksEnabled || !enabledItems[2] == sharedEnabled || !enabledItems[3] == chatEnabled || !enabledItems[4] == adminEnabled) { drawerItems = getResources().getStringArray(R.array.drawerItems); drawerItemsDescriptions = getResources().getStringArray(R.array.drawerItemsDescriptions); @@ -419,15 +420,19 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte if(!chatEnabled) { drawerItemsVisibleList.set(6, false); } - if(!getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) { + if(!adminEnabled) { drawerItemsVisibleList.set(7, false); } + if(!getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) { + drawerItemsVisibleList.set(8, false); + } drawerList.setAdapter(drawerAdapter = new DrawerAdapter(this, drawerItemsList, drawerItemsIconsList, drawerItemsVisibleList)); enabledItems[0] = podcastsEnabled; enabledItems[1] = bookmarksEnabled; enabledItems[2] = sharedEnabled; enabledItems[3] = chatEnabled; + enabledItems[4] = adminEnabled; String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE); if(fragmentType != null && lastSelectedPosition == 0) { diff --git a/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java index ebedf9b1..2afdaf3f 100644 --- a/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java @@ -44,6 +44,7 @@ import java.util.concurrent.TimeUnit; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerState; +import github.daneren2005.dsub.fragments.AdminFragment; import github.daneren2005.dsub.fragments.ChatFragment; import github.daneren2005.dsub.fragments.DownloadFragment; import github.daneren2005.dsub.fragments.MainFragment; @@ -392,6 +393,8 @@ public class SubsonicFragmentActivity extends SubsonicActivity { return new SelectBookmarkFragment(); } else if("Share".equals(fragmentType)) { return new SelectShareFragment(); + } else if("Admin".equals(fragmentType)) { + return new AdminFragment(); } else if("Download".equals(fragmentType)) { return new DownloadFragment(); } else { diff --git a/src/github/daneren2005/dsub/domain/User.java b/src/github/daneren2005/dsub/domain/User.java new file mode 100644 index 00000000..63ead042 --- /dev/null +++ b/src/github/daneren2005/dsub/domain/User.java @@ -0,0 +1,161 @@ +/* + 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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.domain; + +import java.io.Serializable; + +public class User implements Serializable { + private String username; + private String password; + private String email; + private Boolean scrobblingEnabled; + + private Boolean adminRole; + private Boolean settingsRole; + private Boolean downloadRole; + private Boolean uploadRole; + private Boolean playlistRole; + private Boolean coverArtRole; + private Boolean commentRole; + private Boolean podcastRole; + private Boolean streamRole; + private Boolean jukeboxRole; + private Boolean shareRole; + + public User() { + + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public Boolean getScrobblingEnabled() { + return scrobblingEnabled; + } + + public void setScrobblingEnabled(Boolean scrobblingEnabled) { + this.scrobblingEnabled = scrobblingEnabled; + } + + public Boolean getAdminRole() { + return adminRole; + } + + public void setAdminRole(Boolean adminRole) { + this.adminRole = adminRole; + } + + public Boolean getSettingsRole() { + return settingsRole; + } + + public void setSettingsRole(Boolean settingsRole) { + this.settingsRole = settingsRole; + } + + public Boolean getDownloadRole() { + return downloadRole; + } + + public void setDownloadRole(Boolean downloadRole) { + this.downloadRole = downloadRole; + } + + public Boolean getUploadRole() { + return uploadRole; + } + + public void setUploadRole(Boolean uploadRole) { + this.uploadRole = uploadRole; + } + + public Boolean getPlaylistRole() { + return playlistRole; + } + + public void setPlaylistRole(Boolean playlistRole) { + this.playlistRole = playlistRole; + } + + public Boolean getCoverArtRole() { + return coverArtRole; + } + + public void setCoverArtRole(Boolean coverArtRole) { + this.coverArtRole = coverArtRole; + } + + public Boolean getCommentRole() { + return commentRole; + } + + public void setCommentRole(Boolean commentRole) { + this.commentRole = commentRole; + } + + public Boolean getPodcastRole() { + return podcastRole; + } + + public void setPodcastRole(Boolean podcastRole) { + this.podcastRole = podcastRole; + } + + public Boolean getStreamRole() { + return streamRole; + } + + public void setStreamRole(Boolean streamRole) { + this.streamRole = streamRole; + } + + public Boolean getJukeboxRole() { + return jukeboxRole; + } + + public void setJukeboxRole(Boolean jukeboxRole) { + this.jukeboxRole = jukeboxRole; + } + + public Boolean getShareRole() { + return shareRole; + } + + public void setShareRole(Boolean shareRole) { + this.shareRole = shareRole; + } +} diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java new file mode 100644 index 00000000..c43da8d4 --- /dev/null +++ b/src/github/daneren2005/dsub/fragments/AdminFragment.java @@ -0,0 +1,64 @@ +/* + 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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.fragments; + +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; + +import java.util.ArrayList; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.parser.SubsonicRESTException; +import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.view.UserAdapter; + +public class AdminFragment extends SelectListFragment { + @Override + public int getOptionsMenu() { + return R.menu.admin; + } + + @Override + public ArrayAdapter getAdapter(List objs) { + return new UserAdapter(context, objs); + } + + @Override + public List getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { + try { + // Will only work if user is admin + return musicService.getUsers(refresh, context, listener); + } catch(SubsonicRESTException e) { + List users = new ArrayList(); + users.add(musicService.getUser(refresh, "scott", context, listener)); + return users; + } + } + + @Override + public int getTitleResource() { + return R.string.button_bar_admin; + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + + } +} diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index d0740704..7dd5120a 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -41,6 +41,7 @@ import github.daneren2005.dsub.domain.PodcastChannel; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.domain.Share; +import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.domain.Version; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.ProgressListener; @@ -506,6 +507,38 @@ public class CachedMusicService implements MusicService { musicService.deleteBookmark(id, context, progressListener); } + @Override + public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception { + User result = null; + + if(!refresh) { + result = FileUtil.deserialize(context, getCacheName(context, "user"), User.class); + } + + if(result == null) { + result = musicService.getUser(refresh, username, context, progressListener); + FileUtil.serialize(context, result, getCacheName(context, "user")); + } + + return result; + } + + @Override + public List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + List result = null; + + if(!refresh) { + result = FileUtil.deserialize(context, getCacheName(context, "users"), ArrayList.class); + } + + if(result == null) { + result = musicService.getUsers(refresh, context, progressListener); + FileUtil.serialize(context, new ArrayList(result), getCacheName(context, "users")); + } + + return result; + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return musicService.processOfflineSyncs(context, progressListener); diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java index 0522a4be..1164886d 100644 --- a/src/github/daneren2005/dsub/service/MusicService.java +++ b/src/github/daneren2005/dsub/service/MusicService.java @@ -38,6 +38,7 @@ import github.daneren2005.dsub.domain.PodcastChannel; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.domain.Share; +import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.domain.Version; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.ProgressListener; @@ -160,6 +161,10 @@ public interface MusicService { void createBookmark(String id, int position, String comment, Context context, ProgressListener progressListener) throws Exception; void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception; + + User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception; + + List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception; int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception; diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java index cf697441..a809f0d1 100644 --- a/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -46,6 +46,7 @@ import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.PodcastChannel; import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; +import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.ProgressListener; @@ -688,8 +689,18 @@ public class OfflineMusicService extends RESTMusicService { public void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Deleting bookmarks not available in offline mode"); } - - @Override + + @Override + public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Getting user not available in offline mode"); + } + + @Override + public List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Getting users not available in offline mode"); + } + + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ throw new OfflineException("Offline scrobble cached can not be processes while in offline mode"); } diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index eeddcaa2..10647d99 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -88,6 +88,7 @@ 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.UserParser; import github.daneren2005.dsub.service.parser.VersionParser; import github.daneren2005.dsub.service.ssl.SSLSocketFactory; import github.daneren2005.dsub.service.ssl.TrustSelfSignedStrategy; @@ -1189,6 +1190,34 @@ public class RESTMusicService implements MusicService { } } + @Override + public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "getUser", null, Arrays.asList("username"), Arrays.asList(username)); + try { + List users = new UserParser(context).parse(reader, progressListener); + if(users.size() > 0) { + // Should only have returned one anyways + return users.get(0); + } else { + return null; + } + } finally { + Util.close(reader); + } + } + + @Override + public List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception { + checkServerVersion(context, "1.8", "Getting user list is not supported"); + + Reader reader = getReader(context, progressListener, "getUsers", null); + try { + return new UserParser(context).parse(reader, progressListener); + } finally { + Util.close(reader); + } + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return processOfflineScrobbles(context, progressListener) + processOfflineStars(context, progressListener); diff --git a/src/github/daneren2005/dsub/service/parser/UserParser.java b/src/github/daneren2005/dsub/service/parser/UserParser.java new file mode 100644 index 00000000..a66e0b63 --- /dev/null +++ b/src/github/daneren2005/dsub/service/parser/UserParser.java @@ -0,0 +1,73 @@ +/* + 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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.service.parser; + +import android.content.Context; + +import org.xmlpull.v1.XmlPullParser; + +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; + +import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.util.ProgressListener; + +public class UserParser extends AbstractParser { + + public UserParser(Context context) { + super(context); + } + + public List parse(Reader reader, ProgressListener progressListener) throws Exception { + init(reader); + List result = new ArrayList(); + int eventType; + + do { + eventType = nextParseEvent(); + if (eventType == XmlPullParser.START_TAG) { + String name = getElementName(); + if ("user".equals(name)) { + User user = new User(); + + user.setUsername(get("username")); + user.setEmail(get("email")); + user.setScrobblingEnabled(getBoolean("scrobblingEnabled")); + user.setAdminRole(getBoolean("adminRole")); + user.setSettingsRole(getBoolean("settingsRole")); + user.setDownloadRole(getBoolean("downloadRole")); + user.setUploadRole(getBoolean("uploadRole")); + user.setPlaylistRole(getBoolean("playlistRole")); + user.setCoverArtRole(getBoolean("coverArtRole")); + user.setCommentRole(getBoolean("commentRole")); + user.setPodcastRole(getBoolean("podcastRole")); + user.setStreamRole(getBoolean("streamRole")); + user.setJukeboxRole(getBoolean("jukeboxRole")); + user.setShareRole(getBoolean("shareRole")); + + result.add(user); + } else if ("error".equals(name)) { + handleError(); + } + } + } while (eventType != XmlPullParser.END_DOCUMENT); + + validate(); + + return result; + } +} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/util/Constants.java b/src/github/daneren2005/dsub/util/Constants.java index 2b7f8757..34bf734d 100644 --- a/src/github/daneren2005/dsub/util/Constants.java +++ b/src/github/daneren2005/dsub/util/Constants.java @@ -141,6 +141,7 @@ public final class Constants { public static final String PREFERENCES_KEY_OVERRIDE_SYSTEM_LANGUAGE = "overrideSystemLanguage"; public static final String PREFERENCES_KEY_PLAY_NOW_AFTER = "playNowAfter"; public static final String PREFERENCES_KEY_LARGE_ALBUM_ART = "largeAlbumArt"; + public static final String PREFERENCES_KEY_ADMIN_ENABLED = "adminEnabled"; public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; diff --git a/src/github/daneren2005/dsub/view/UserAdapter.java b/src/github/daneren2005/dsub/view/UserAdapter.java new file mode 100644 index 00000000..8aaa261c --- /dev/null +++ b/src/github/daneren2005/dsub/view/UserAdapter.java @@ -0,0 +1,49 @@ +/* + 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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; + +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.User; + +public class UserAdapter extends ArrayAdapter { + + private final Context activity; + + public UserAdapter(Context activity, List users) { + super(activity, R.layout.basic_list_item, users); + this.activity = activity; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + User entry = getItem(position); + UserView view; + if (convertView != null && convertView instanceof UserView) { + view = (UserView) convertView; + } else { + view = new UserView(activity); + } + view.setObject(entry); + return view; + } +} \ No newline at end of file diff --git a/src/github/daneren2005/dsub/view/UserView.java b/src/github/daneren2005/dsub/view/UserView.java new file mode 100644 index 00000000..f966f28f --- /dev/null +++ b/src/github/daneren2005/dsub/view/UserView.java @@ -0,0 +1,50 @@ +/* + 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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.User; + +public class UserView extends UpdateView { + private User user; + + private TextView userNameView; + + public UserView(Context context) { + super(context); + this.context = context; + LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); + + userNameView = (TextView) findViewById(R.id.item_name); + moreButton = (ImageView) findViewById(R.id.item_more); + moreButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View v) { + v.showContextMenu(); + } + }); + } + + protected void setObjectImpl(Object obj) { + this.user = (User) obj; + userNameView.setText(user.getUsername()); + } +} -- cgit v1.2.3 From b573caa53594995e5587d62e1f4d999452e23a41 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 9 Jun 2014 06:21:04 -0700 Subject: #171 Add more stubs to Admin tab --- res/menu/admin_context.xml | 16 ++++++++ res/values/strings.xml | 4 ++ .../daneren2005/dsub/fragments/AdminFragment.java | 41 +++++++++++++++++++- .../dsub/service/CachedMusicService.java | 29 +++++++++++++- .../daneren2005/dsub/service/MusicService.java | 10 +++++ .../dsub/service/OfflineMusicService.java | 25 ++++++++++++ .../daneren2005/dsub/service/RESTMusicService.java | 45 ++++++++++++++++++++++ src/github/daneren2005/dsub/util/Util.java | 5 +++ 8 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 res/menu/admin_context.xml (limited to 'src') diff --git a/res/menu/admin_context.xml b/res/menu/admin_context.xml new file mode 100644 index 00000000..e4948acd --- /dev/null +++ b/res/menu/admin_context.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 0e385186..8fb6f164 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -447,6 +447,10 @@ Share via Delete Share + Update Permissions + Change Password + Delete User + A network error occurred. Retrying %1$d of %2$d. Please wait... diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java index c43da8d4..716279cb 100644 --- a/src/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/src/github/daneren2005/dsub/fragments/AdminFragment.java @@ -15,10 +15,15 @@ package github.daneren2005.dsub.fragments; +import android.util.Log; +import android.view.ContextMenu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -27,9 +32,37 @@ import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.parser.SubsonicRESTException; import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.UserAdapter; public class AdminFragment extends SelectListFragment { + private static String TAG = AdminFragment.class.getSimpleName(); + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, view, menuInfo); + + MenuInflater inflater = context.getMenuInflater(); + inflater.inflate(R.menu.admin_context, menu); + } + + @Override + public boolean onContextItemSelected(MenuItem menuItem) { + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); + User user = objects.get(info.position); + + switch(menuItem.getItemId()) { + case R.id.admin_update_permissions: + break; + case R.id.admin_change_password: + break; + case R.id.admin_delete_user: + break; + } + + return true; + } + @Override public int getOptionsMenu() { return R.menu.admin; @@ -46,8 +79,14 @@ public class AdminFragment extends SelectListFragment { // Will only work if user is admin return musicService.getUsers(refresh, context, listener); } catch(SubsonicRESTException e) { + // Delete cached users if not allowed to get them + String s = Util.getRestUrl(context, null, false); + String cache = "users-" + s.hashCode() + ".ser"; + File file = new File(context.getCacheDir(), cache); + file.delete(); + List users = new ArrayList(); - users.add(musicService.getUser(refresh, "scott", context, listener)); + users.add(musicService.getUser(refresh, Util.getCurrentUsername(context), context, listener)); return users; } } diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index 7dd5120a..e14b4d84 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -512,12 +512,12 @@ public class CachedMusicService implements MusicService { User result = null; if(!refresh) { - result = FileUtil.deserialize(context, getCacheName(context, "user"), User.class); + result = FileUtil.deserialize(context, getCacheName(context, "user-" + username), User.class); } if(result == null) { result = musicService.getUser(refresh, username, context, progressListener); - FileUtil.serialize(context, result, getCacheName(context, "user")); + FileUtil.serialize(context, result, getCacheName(context, "user-" + username)); } return result; @@ -539,6 +539,31 @@ public class CachedMusicService implements MusicService { return result; } + @Override + public void createUser(User user, Context context, ProgressListener progressListener) throws Exception { + musicService.createUser(user, context, progressListener); + } + + @Override + public void updateUser(User user, Context context, ProgressListener progressListener) throws Exception { + musicService.updateUser(user, context, progressListener); + } + + @Override + public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception { + musicService.deleteUser(username, context, progressListener); + } + + @Override + public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { + musicService.changePassword(username, password, context, progressListener); + } + + @Override + public Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception { + return musicService.getAvatar(username, context, progressListener); + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return musicService.processOfflineSyncs(context, progressListener); diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java index 1164886d..6f58603c 100644 --- a/src/github/daneren2005/dsub/service/MusicService.java +++ b/src/github/daneren2005/dsub/service/MusicService.java @@ -165,6 +165,16 @@ public interface MusicService { User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception; List getUsers(boolean refresh, Context context, ProgressListener progressListener) throws Exception; + + void createUser(User user, Context context, ProgressListener progressListener) throws Exception; + + void updateUser(User user, Context context, ProgressListener progressListener) throws Exception; + + void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception; + + void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception; + + Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception; int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception; diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java index a809f0d1..9e2b9e13 100644 --- a/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -700,6 +700,31 @@ public class OfflineMusicService extends RESTMusicService { throw new OfflineException("Getting users not available in offline mode"); } + @Override + public void createUser(User user, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Creating users not available in offline mode"); + } + + @Override + public void updateUser(User user, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Updating users not available in offline mode"); + } + + @Override + public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Deleting users not available in offline mode"); + } + + @Override + public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Changing passwords not available in offline mode"); + } + + @Override + public Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception { + return null; + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ throw new OfflineException("Offline scrobble cached can not be processes while in offline mode"); diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index 10647d99..20328d54 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -1218,6 +1218,51 @@ public class RESTMusicService implements MusicService { } } + @Override + public void createUser(User user, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "createUser", null); + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } + } + + @Override + public void updateUser(User user, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "createUser", null); + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } + } + + @Override + public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "deleteUser", null, Arrays.asList("username"), Arrays.asList(username)); + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } + } + + @Override + public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "changePassword", null, Arrays.asList("username", "password"), Arrays.asList(username, password)); + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } + } + + @Override + public Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception { + return null; + } + @Override public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{ return processOfflineScrobbles(context, progressListener) + processOfflineStars(context, progressListener); diff --git a/src/github/daneren2005/dsub/util/Util.java b/src/github/daneren2005/dsub/util/Util.java index b62b3382..dad557e3 100644 --- a/src/github/daneren2005/dsub/util/Util.java +++ b/src/github/daneren2005/dsub/util/Util.java @@ -169,6 +169,11 @@ public final class Util { SharedPreferences prefs = getPreferences(context); return prefs.getBoolean(Constants.PREFERENCES_KEY_OFFLINE, false) ? 0 : prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); } + + public static String getCurrentUsername(Context context) { + SharedPreferences prefs = getPreferences(context); + return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + getActiveServer(context), null); + } public static boolean checkServerVersion(Context context, String requiredVersion) { Version version = Util.getServerRestVersion(context); -- cgit v1.2.3 From ab1814ea9b50feebce21aff2759172d7193afa7a Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 9 Jun 2014 19:46:44 -0700 Subject: #171 Add change password, delete user, start of user settings fragment --- res/layout/change_password.xml | 28 ++++++ res/values/strings.xml | 6 ++ .../daneren2005/dsub/fragments/AdminFragment.java | 105 +++++++++++++++++++++ .../dsub/fragments/SelectListFragment.java | 6 +- .../daneren2005/dsub/fragments/UserFragment.java | 61 ++++++++++++ .../dsub/service/CachedMusicService.java | 4 + src/github/daneren2005/dsub/view/UserAdapter.java | 1 - 7 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 res/layout/change_password.xml create mode 100644 src/github/daneren2005/dsub/fragments/UserFragment.java (limited to 'src') diff --git a/res/layout/change_password.xml b/res/layout/change_password.xml new file mode 100644 index 00000000..ad3e9cd8 --- /dev/null +++ b/res/layout/change_password.xml @@ -0,0 +1,28 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 8fb6f164..3148ae99 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -449,7 +449,13 @@ Update Permissions Change Password + Successfully changed password for %1$s + Failed to change password for %1$s + New Password: + Enter a valid password Delete User + Successfully deleted %1$s + Failed to delete %1$s A network error occurred. Retrying %1$d of %2$d. diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java index 716279cb..f6e8e153 100644 --- a/src/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/src/github/daneren2005/dsub/fragments/AdminFragment.java @@ -15,6 +15,9 @@ package github.daneren2005.dsub.fragments; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.os.Bundle; import android.util.Log; import android.view.ContextMenu; import android.view.MenuInflater; @@ -22,6 +25,7 @@ import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.TextView; import java.io.File; import java.util.ArrayList; @@ -30,8 +34,13 @@ import java.util.List; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.service.OfflineException; +import github.daneren2005.dsub.service.ServerTooOldException; import github.daneren2005.dsub.service.parser.SubsonicRESTException; +import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.UserAdapter; @@ -55,8 +64,10 @@ public class AdminFragment extends SelectListFragment { case R.id.admin_update_permissions: break; case R.id.admin_change_password: + changePassword(user); break; case R.id.admin_delete_user: + deleteUser(user); break; } @@ -98,6 +109,100 @@ public class AdminFragment extends SelectListFragment { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { + User user = (User) parent.getItemAtPosition(position); + SubsonicFragment fragment = new UserFragment(); + Bundle args = new Bundle(); + args.putSerializable(Constants.INTENT_EXTRA_NAME_ID, user); + fragment.setArguments(args); + + replaceFragment(fragment); + } + + private void changePassword(final User user) { + View layout = context.getLayoutInflater().inflate(R.layout.change_password, null); + final TextView passwordView = (TextView) layout.findViewById(R.id.new_password); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.admin_change_password) + .setView(layout) + .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + final String password = passwordView.getText().toString(); + // Don't allow blank passwords + if ("".equals(password)) { + Util.toast(context, R.string.admin_change_password_invalid); + return; + } + + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.changePassword(user.getUsername(), password, context, null); + return null; + } + + @Override + protected void done(Void v) { + Util.toast(context, context.getResources().getString(R.string.admin_change_password_success, user.getUsername())); + } + + @Override + protected void error(Throwable error) { + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.admin_change_password_error, user.getUsername()); + } + + Util.toast(context, msg); + } + }.execute(); + } + }) + .setNegativeButton(R.string.common_cancel, null) + .setCancelable(true); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + private void deleteUser(final User user) { + Util.confirmDialog(context, R.string.common_delete, user.getUsername(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.deleteUser(user.getUsername(), context, null); + return null; + } + + @Override + protected void done(Void v) { + adapter.remove(user); + adapter.notifyDataSetChanged(); + + Util.toast(context, context.getResources().getString(R.string.admin_delete_user_success, user.getUsername())); + } + + @Override + protected void error(Throwable error) { + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.admin_delete_user_error, user.getUsername()); + } + + Util.toast(context, msg); + } + }.execute(); + } + }); } } diff --git a/src/github/daneren2005/dsub/fragments/SelectListFragment.java b/src/github/daneren2005/dsub/fragments/SelectListFragment.java index 4938fb3b..1c77ad68 100644 --- a/src/github/daneren2005/dsub/fragments/SelectListFragment.java +++ b/src/github/daneren2005/dsub/fragments/SelectListFragment.java @@ -107,12 +107,14 @@ public abstract class SelectListFragment extends SubsonicFragment implements @Override public boolean onOptionsItemSelected(MenuItem item) { return super.onOptionsItemSelected(item); - } @Override protected void refresh(final boolean refresh) { - setTitle(getTitleResource()); + int titleRes = getTitleResource(); + if(titleRes != 0) { + setTitle(getTitleResource()); + } listView.setVisibility(View.INVISIBLE); emptyView.setVisibility(View.GONE); diff --git a/src/github/daneren2005/dsub/fragments/UserFragment.java b/src/github/daneren2005/dsub/fragments/UserFragment.java new file mode 100644 index 00000000..3a85c6bb --- /dev/null +++ b/src/github/daneren2005/dsub/fragments/UserFragment.java @@ -0,0 +1,61 @@ +/* + 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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.fragments; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.util.Constants; + +public class UserFragment extends SubsonicFragment{ + private ListView listView; + private LayoutInflater inflater; + private User user; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { + this.inflater = inflater; + rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); + + Bundle args = getArguments(); + user = (User) args.getSerializable(Constants.INTENT_EXTRA_NAME_ID); + setTitle(user.getUsername()); + + return rootView; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { + if(!primaryFragment) { + return; + } + + menuInflater.inflate(R.menu.empty, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return super.onOptionsItemSelected(item); + } +} diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index e14b4d84..1f1715c4 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -552,6 +552,10 @@ public class CachedMusicService implements MusicService { @Override public void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception { musicService.deleteUser(username, context, progressListener); + + // Delete cached users if any have been removed from list + File file = new File(context.getCacheDir(), getCacheName(context, "users")); + file.delete(); } @Override diff --git a/src/github/daneren2005/dsub/view/UserAdapter.java b/src/github/daneren2005/dsub/view/UserAdapter.java index 8aaa261c..937e2e92 100644 --- a/src/github/daneren2005/dsub/view/UserAdapter.java +++ b/src/github/daneren2005/dsub/view/UserAdapter.java @@ -26,7 +26,6 @@ import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; public class UserAdapter extends ArrayAdapter { - private final Context activity; public UserAdapter(Context activity, List users) { -- cgit v1.2.3 From de81b9b43c92a6a8a1403c4547dc44dd17b9792e Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Mon, 9 Jun 2014 22:20:22 -0700 Subject: #171 Add a full UserFragment to view/edit settings --- res/menu/admin_context.xml | 4 - res/menu/user.xml | 14 +++ res/values/strings.xml | 2 + src/github/daneren2005/dsub/domain/User.java | 126 ++++----------------- .../daneren2005/dsub/fragments/AdminFragment.java | 2 - .../daneren2005/dsub/fragments/UserFragment.java | 57 +++++++++- .../dsub/service/CachedMusicService.java | 4 + .../daneren2005/dsub/service/RESTMusicService.java | 17 ++- .../dsub/service/parser/UserParser.java | 28 +++-- src/github/daneren2005/dsub/view/SettingView.java | 68 +++++++++++ .../daneren2005/dsub/view/SettingsAdapter.java | 51 +++++++++ 11 files changed, 250 insertions(+), 123 deletions(-) create mode 100644 res/menu/user.xml create mode 100644 src/github/daneren2005/dsub/view/SettingView.java create mode 100644 src/github/daneren2005/dsub/view/SettingsAdapter.java (limited to 'src') diff --git a/res/menu/admin_context.xml b/res/menu/admin_context.xml index e4948acd..8cd04859 100644 --- a/res/menu/admin_context.xml +++ b/res/menu/admin_context.xml @@ -2,10 +2,6 @@ - - diff --git a/res/menu/user.xml b/res/menu/user.xml new file mode 100644 index 00000000..ace011b1 --- /dev/null +++ b/res/menu/user.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index add99c11..460e46db 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -448,6 +448,8 @@ Delete Share Update Permissions + Successfully updated permission for %1$s + Failed to update permissions for %1$s Change Password Successfully changed password for %1$s Failed to change password for %1$s diff --git a/src/github/daneren2005/dsub/domain/User.java b/src/github/daneren2005/dsub/domain/User.java index 63ead042..d970366c 100644 --- a/src/github/daneren2005/dsub/domain/User.java +++ b/src/github/daneren2005/dsub/domain/User.java @@ -16,24 +16,15 @@ package github.daneren2005.dsub.domain; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; public class User implements Serializable { private String username; private String password; private String email; - private Boolean scrobblingEnabled; - - private Boolean adminRole; - private Boolean settingsRole; - private Boolean downloadRole; - private Boolean uploadRole; - private Boolean playlistRole; - private Boolean coverArtRole; - private Boolean commentRole; - private Boolean podcastRole; - private Boolean streamRole; - private Boolean jukeboxRole; - private Boolean shareRole; + + private List settings = new ArrayList(); public User() { @@ -63,99 +54,30 @@ public class User implements Serializable { this.email = email; } - public Boolean getScrobblingEnabled() { - return scrobblingEnabled; - } - - public void setScrobblingEnabled(Boolean scrobblingEnabled) { - this.scrobblingEnabled = scrobblingEnabled; - } - - public Boolean getAdminRole() { - return adminRole; - } - - public void setAdminRole(Boolean adminRole) { - this.adminRole = adminRole; - } - - public Boolean getSettingsRole() { - return settingsRole; - } - - public void setSettingsRole(Boolean settingsRole) { - this.settingsRole = settingsRole; - } - - public Boolean getDownloadRole() { - return downloadRole; - } - - public void setDownloadRole(Boolean downloadRole) { - this.downloadRole = downloadRole; - } - - public Boolean getUploadRole() { - return uploadRole; - } - - public void setUploadRole(Boolean uploadRole) { - this.uploadRole = uploadRole; - } - - public Boolean getPlaylistRole() { - return playlistRole; + public List getSettings() { + return settings; } - - public void setPlaylistRole(Boolean playlistRole) { - this.playlistRole = playlistRole; - } - - public Boolean getCoverArtRole() { - return coverArtRole; + public void addSetting(String name, Boolean value) { + settings.add(new Setting(name, value)); } - public void setCoverArtRole(Boolean coverArtRole) { - this.coverArtRole = coverArtRole; - } - - public Boolean getCommentRole() { - return commentRole; - } + public static class Setting implements Serializable { + String name; + Boolean value; - public void setCommentRole(Boolean commentRole) { - this.commentRole = commentRole; - } - - public Boolean getPodcastRole() { - return podcastRole; - } - - public void setPodcastRole(Boolean podcastRole) { - this.podcastRole = podcastRole; - } - - public Boolean getStreamRole() { - return streamRole; - } - - public void setStreamRole(Boolean streamRole) { - this.streamRole = streamRole; - } - - public Boolean getJukeboxRole() { - return jukeboxRole; - } - - public void setJukeboxRole(Boolean jukeboxRole) { - this.jukeboxRole = jukeboxRole; - } - - public Boolean getShareRole() { - return shareRole; - } + public Setting(String name, Boolean value) { + this.name = name; + this.value = value; + } - public void setShareRole(Boolean shareRole) { - this.shareRole = shareRole; + public String getName() { + return name; + } + public Boolean getValue() { + return value; + } + public void setValue(Boolean value) { + this.value = value; + } } } diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java index f6e8e153..faa7529a 100644 --- a/src/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/src/github/daneren2005/dsub/fragments/AdminFragment.java @@ -61,8 +61,6 @@ public class AdminFragment extends SelectListFragment { User user = objects.get(info.position); switch(menuItem.getItemId()) { - case R.id.admin_update_permissions: - break; case R.id.admin_change_password: changePassword(user); break; diff --git a/src/github/daneren2005/dsub/fragments/UserFragment.java b/src/github/daneren2005/dsub/fragments/UserFragment.java index 3a85c6bb..1f4d4592 100644 --- a/src/github/daneren2005/dsub/fragments/UserFragment.java +++ b/src/github/daneren2005/dsub/fragments/UserFragment.java @@ -16,6 +16,7 @@ package github.daneren2005.dsub.fragments; import android.os.Bundle; +import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -26,7 +27,14 @@ import android.widget.ListView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.service.OfflineException; +import github.daneren2005.dsub.service.ServerTooOldException; import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.SilentBackgroundTask; +import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.SettingsAdapter; public class UserFragment extends SubsonicFragment{ private ListView listView; @@ -38,8 +46,15 @@ public class UserFragment extends SubsonicFragment{ this.inflater = inflater; rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); + refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); + refreshLayout.setEnabled(false); + Bundle args = getArguments(); user = (User) args.getSerializable(Constants.INTENT_EXTRA_NAME_ID); + + listView = (ListView)rootView.findViewById(R.id.fragment_list); + listView.setAdapter(new SettingsAdapter(context, user.getSettings(), true)); + setTitle(user.getUsername()); return rootView; @@ -51,11 +66,49 @@ public class UserFragment extends SubsonicFragment{ return; } - menuInflater.inflate(R.menu.empty, menu); + menuInflater.inflate(R.menu.user, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); + if(super.onOptionsItemSelected(item)) { + return true; + } + + switch (item.getItemId()) { + case R.id.menu_update_permissions: + updateSettings(); + return true; + } + + return false; + } + + private void updateSettings() { + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.updateUser(user, context, null); + return null; + } + + @Override + protected void done(Void v) { + Util.toast(context, context.getResources().getString(R.string.admin_update_permissions_success, user.getUsername())); + } + + @Override + protected void error(Throwable error) { + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.admin_update_permissions_error, user.getUsername()); + } + + Util.toast(context, msg); + } + }.execute(); } } diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index 1f1715c4..86289511 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -547,6 +547,10 @@ public class CachedMusicService implements MusicService { @Override public void updateUser(User user, Context context, ProgressListener progressListener) throws Exception { musicService.updateUser(user, context, progressListener); + + // Delete cached users if anything updated + File file = new File(context.getCacheDir(), getCacheName(context, "users")); + file.delete(); } @Override diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index 20328d54..c2f64dad 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -1230,7 +1230,22 @@ public class RESTMusicService implements MusicService { @Override public void updateUser(User user, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "createUser", null); + checkServerVersion(context, "1.10", "Updating user is not supported"); + + List names = new ArrayList(); + List values = new ArrayList(); + + names.add("username"); + values.add(user.getUsername()); + + for(User.Setting setting: user.getSettings()) { + if(setting.getName().indexOf("Role") != -1) { + names.add(setting.getName()); + values.add(setting.getValue()); + } + } + + Reader reader = getReader(context, progressListener, "updateUser", null, names, values); try { new ErrorParser(context).parse(reader); } finally { diff --git a/src/github/daneren2005/dsub/service/parser/UserParser.java b/src/github/daneren2005/dsub/service/parser/UserParser.java index a66e0b63..5b2f8fc1 100644 --- a/src/github/daneren2005/dsub/service/parser/UserParser.java +++ b/src/github/daneren2005/dsub/service/parser/UserParser.java @@ -46,18 +46,18 @@ public class UserParser extends AbstractParser { user.setUsername(get("username")); user.setEmail(get("email")); - user.setScrobblingEnabled(getBoolean("scrobblingEnabled")); - user.setAdminRole(getBoolean("adminRole")); - user.setSettingsRole(getBoolean("settingsRole")); - user.setDownloadRole(getBoolean("downloadRole")); - user.setUploadRole(getBoolean("uploadRole")); - user.setPlaylistRole(getBoolean("playlistRole")); - user.setCoverArtRole(getBoolean("coverArtRole")); - user.setCommentRole(getBoolean("commentRole")); - user.setPodcastRole(getBoolean("podcastRole")); - user.setStreamRole(getBoolean("streamRole")); - user.setJukeboxRole(getBoolean("jukeboxRole")); - user.setShareRole(getBoolean("shareRole")); + parseSetting(user, "scrobblingEnabled"); + parseSetting(user, "adminRole"); + parseSetting(user, "settingsRole"); + parseSetting(user, "downloadRole"); + parseSetting(user, "uploadRole"); + // Depreciated: parseSetting(user, "playlistRole"); + parseSetting(user, "coverArtRole"); + parseSetting(user, "commentRole"); + parseSetting(user, "podcastRole"); + parseSetting(user, "streamRole"); + parseSetting(user, "jukeboxRole"); + parseSetting(user, "shareRole"); result.add(user); } else if ("error".equals(name)) { @@ -70,4 +70,8 @@ public class UserParser extends AbstractParser { return result; } + + private void parseSetting(User user, String name) { + user.addSetting(name, getBoolean(name)); + } } \ No newline at end of file diff --git a/src/github/daneren2005/dsub/view/SettingView.java b/src/github/daneren2005/dsub/view/SettingView.java new file mode 100644 index 00000000..f2669551 --- /dev/null +++ b/src/github/daneren2005/dsub/view/SettingView.java @@ -0,0 +1,68 @@ +/* + 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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckedTextView; + +import static github.daneren2005.dsub.domain.User.Setting; + +public class SettingView extends UpdateView { + Setting setting; + + CheckedTextView view; + + public SettingView(Context context) { + super(context); + this.context = context; + LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_multiple_choice, this, true); + + view = (CheckedTextView) findViewById(android.R.id.text1); + } + + protected void setObjectImpl(Object obj, Object editable) { + this.setting = (Setting) obj; + + String display = setting.getName(); + // Can't edit non-role parts + if(display.indexOf("Role") == -1) { + editable = false; + } + display = display.replace("Role", ""); + display = Character.toUpperCase(display.charAt(0)) + display.substring(1); + + view.setText(display); + if(setting.getValue()) { + view.setChecked(setting.getValue()); + } else { + view.setChecked(false); + } + + if((Boolean) editable) { + view.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + view.toggle(); + setting.setValue(view.isChecked()); + } + }); + } else { + view.setOnClickListener(null); + } + } +} diff --git a/src/github/daneren2005/dsub/view/SettingsAdapter.java b/src/github/daneren2005/dsub/view/SettingsAdapter.java new file mode 100644 index 00000000..88019c00 --- /dev/null +++ b/src/github/daneren2005/dsub/view/SettingsAdapter.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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; + +import java.util.List; + +import github.daneren2005.dsub.R; + +import static github.daneren2005.dsub.domain.User.Setting; + +public class SettingsAdapter extends ArrayAdapter { + private final Context context; + private final boolean editable; + + public SettingsAdapter(Context context, List settings, boolean editable) { + super(context, R.layout.basic_list_item, settings); + this.context = context; + this.editable = editable; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + Setting entry = getItem(position); + SettingView view; + if (convertView != null && convertView instanceof SettingView) { + view = (SettingView) convertView; + } else { + view = new SettingView(context); + } + view.setObject(entry, editable); + return view; + } +} -- cgit v1.2.3 From 42843c2b45668064aee7ce985bb941acb54f5eac Mon Sep 17 00:00:00 2001 From: daneren2005 Date: Tue, 10 Jun 2014 15:58:00 -0700 Subject: Add empty constructor for serializer --- src/github/daneren2005/dsub/domain/User.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/github/daneren2005/dsub/domain/User.java b/src/github/daneren2005/dsub/domain/User.java index d970366c..ca124a58 100644 --- a/src/github/daneren2005/dsub/domain/User.java +++ b/src/github/daneren2005/dsub/domain/User.java @@ -65,6 +65,9 @@ public class User implements Serializable { String name; Boolean value; + public Setting() { + + } public Setting(String name, Boolean value) { this.name = name; this.value = value; -- cgit v1.2.3 From f064378307cf651c1f0cb82a36b81099b4db7401 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 10 Jun 2014 19:24:00 -0700 Subject: #171 Only display admin stuff if user is an admin --- res/menu/admin_context_user.xml | 8 +++ .../dsub/activity/SubsonicFragmentActivity.java | 3 + .../daneren2005/dsub/fragments/AdminFragment.java | 15 +++- .../daneren2005/dsub/fragments/MainFragment.java | 6 +- .../daneren2005/dsub/fragments/UserFragment.java | 9 ++- src/github/daneren2005/dsub/util/UserUtil.java | 79 ++++++++++++++++++++++ src/github/daneren2005/dsub/util/Util.java | 13 ---- src/github/daneren2005/dsub/view/ChatAdapter.java | 3 +- 8 files changed, 116 insertions(+), 20 deletions(-) create mode 100644 res/menu/admin_context_user.xml create mode 100644 src/github/daneren2005/dsub/util/UserUtil.java (limited to 'src') diff --git a/res/menu/admin_context_user.xml b/res/menu/admin_context_user.xml new file mode 100644 index 00000000..cc4c1ab9 --- /dev/null +++ b/res/menu/admin_context_user.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java index 2afdaf3f..7fafae60 100644 --- a/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java @@ -63,6 +63,7 @@ import github.daneren2005.dsub.util.BackgroundTask; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.SilentBackgroundTask; +import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.ChangeLog; @@ -467,6 +468,8 @@ public class SubsonicFragmentActivity extends SubsonicActivity { editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 3); editor.commit(); } + + UserUtil.seedCurrentUser(this); } private void resetCacheLocation(SharedPreferences prefs) { diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java index faa7529a..b7f09532 100644 --- a/src/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/src/github/daneren2005/dsub/fragments/AdminFragment.java @@ -41,6 +41,7 @@ import github.daneren2005.dsub.service.parser.SubsonicRESTException; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.SilentBackgroundTask; +import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.UserAdapter; @@ -52,7 +53,11 @@ public class AdminFragment extends SelectListFragment { super.onCreateContextMenu(menu, view, menuInfo); MenuInflater inflater = context.getMenuInflater(); - inflater.inflate(R.menu.admin_context, menu); + if(UserUtil.isCurrentAdmin(context) && Util.checkServerVersion(context, "1.10")) { + inflater.inflate(R.menu.admin_context, menu); + } else { + inflater.inflate(R.menu.admin_context_user, menu); + } } @Override @@ -74,7 +79,11 @@ public class AdminFragment extends SelectListFragment { @Override public int getOptionsMenu() { - return R.menu.admin; + if(UserUtil.isCurrentAdmin(context)) { + return R.menu.admin; + } else { + return R.menu.empty; + } } @Override @@ -95,7 +104,7 @@ public class AdminFragment extends SelectListFragment { file.delete(); List users = new ArrayList(); - users.add(musicService.getUser(refresh, Util.getCurrentUsername(context), context, listener)); + users.add(musicService.getUser(refresh, UserUtil.getCurrentUsername(context), context, listener)); return users; } } diff --git a/src/github/daneren2005/dsub/fragments/MainFragment.java b/src/github/daneren2005/dsub/fragments/MainFragment.java index 88baf717..e9f06e45 100644 --- a/src/github/daneren2005/dsub/fragments/MainFragment.java +++ b/src/github/daneren2005/dsub/fragments/MainFragment.java @@ -25,6 +25,7 @@ import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.LoadingTask; import github.daneren2005.dsub.util.Pair; +import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.view.MergeAdapter; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.service.MusicService; @@ -207,6 +208,7 @@ public class MainFragment extends SubsonicFragment { } Util.setActiveServer(context, instance); context.invalidate(); + UserUtil.seedCurrentUser(context); } } @@ -218,13 +220,15 @@ public class MainFragment extends SubsonicFragment { if (service != null) { service.setOnline(isOffline); } - + + // Coming back online if(isOffline) { int scrobblesCount = Util.offlineScrobblesCount(context); int starsCount = Util.offlineStarsCount(context); if(scrobblesCount > 0 || starsCount > 0){ showOfflineSyncDialog(scrobblesCount, starsCount); } + UserUtil.seedCurrentUser(context); } } diff --git a/src/github/daneren2005/dsub/fragments/UserFragment.java b/src/github/daneren2005/dsub/fragments/UserFragment.java index 1f4d4592..f2af85fb 100644 --- a/src/github/daneren2005/dsub/fragments/UserFragment.java +++ b/src/github/daneren2005/dsub/fragments/UserFragment.java @@ -33,6 +33,7 @@ import github.daneren2005.dsub.service.OfflineException; import github.daneren2005.dsub.service.ServerTooOldException; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.SilentBackgroundTask; +import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.SettingsAdapter; @@ -53,7 +54,7 @@ public class UserFragment extends SubsonicFragment{ user = (User) args.getSerializable(Constants.INTENT_EXTRA_NAME_ID); listView = (ListView)rootView.findViewById(R.id.fragment_list); - listView.setAdapter(new SettingsAdapter(context, user.getSettings(), true)); + listView.setAdapter(new SettingsAdapter(context, user.getSettings(), UserUtil.isCurrentAdmin(context))); setTitle(user.getUsername()); @@ -66,7 +67,11 @@ public class UserFragment extends SubsonicFragment{ return; } - menuInflater.inflate(R.menu.user, menu); + if(UserUtil.isCurrentAdmin(context)) { + menuInflater.inflate(R.menu.user, menu); + } else { + menuInflater.inflate(R.menu.empty, menu); + } } @Override diff --git a/src/github/daneren2005/dsub/util/UserUtil.java b/src/github/daneren2005/dsub/util/UserUtil.java new file mode 100644 index 00000000..5158829c --- /dev/null +++ b/src/github/daneren2005/dsub/util/UserUtil.java @@ -0,0 +1,79 @@ +/* + 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 . + Copyright 2014 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.util; + +import android.content.Context; +import android.content.SharedPreferences; + +import java.io.File; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.service.MusicServiceFactory; + +public final class UserUtil { + private static User currentUser; + + public static void seedCurrentUser(final Context context) { + // Only try to seed if online + if(Util.isOffline(context)) { + return; + } + + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + currentUser = MusicServiceFactory.getMusicService(context).getUser(false, getCurrentUsername(context), context, null); + return null; + } + }.execute(); + } + + public static User getCurrentUser(Context context) { + return currentUser; + } + + public static String getCurrentUsername(Context context, int instance) { + SharedPreferences prefs = Util.getPreferences(context); + return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null); + } + + public static String getCurrentUsername(Context context) { + return getCurrentUsername(context, Util.getActiveServer(context)); + } + + public static boolean isCurrentAdmin(Context context) { + if(currentUser == null) { + return false; + } else { + return isCurrentRole(context, "adminRole"); + } + } + + public static boolean isCurrentRole(Context context, String role) { + if(currentUser == null) { + return false; + } + + for(User.Setting setting: currentUser.getSettings()) { + if(setting.getName().equals(role)) { + return setting.getValue() == true; + } + } + + return false; + } +} diff --git a/src/github/daneren2005/dsub/util/Util.java b/src/github/daneren2005/dsub/util/Util.java index dad557e3..931aa590 100644 --- a/src/github/daneren2005/dsub/util/Util.java +++ b/src/github/daneren2005/dsub/util/Util.java @@ -169,11 +169,6 @@ public final class Util { SharedPreferences prefs = getPreferences(context); return prefs.getBoolean(Constants.PREFERENCES_KEY_OFFLINE, false) ? 0 : prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1); } - - public static String getCurrentUsername(Context context) { - SharedPreferences prefs = getPreferences(context); - return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + getActiveServer(context), null); - } public static boolean checkServerVersion(Context context, String requiredVersion) { Version version = Util.getServerRestVersion(context); @@ -231,14 +226,6 @@ 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) { int instance = getActiveServer(context); diff --git a/src/github/daneren2005/dsub/view/ChatAdapter.java b/src/github/daneren2005/dsub/view/ChatAdapter.java index 518f81ef..c7bc13f2 100644 --- a/src/github/daneren2005/dsub/view/ChatAdapter.java +++ b/src/github/daneren2005/dsub/view/ChatAdapter.java @@ -10,6 +10,7 @@ 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.UserUtil; import github.daneren2005.dsub.util.Util; import java.text.DateFormat; @@ -47,7 +48,7 @@ public class ChatAdapter extends ArrayAdapter { Date messageTime = new java.util.Date(message.getTime()); String messageText = message.getMessage(); - String me = Util.getUserName(activity, Util.getActiveServer(activity)); + String me = UserUtil.getCurrentUsername(activity); if (messageUser.equals(me)) { layout = R.layout.chat_item_reverse; -- cgit v1.2.3 From 2b079541a39f08be590cb2b37e2d401edcb4f13e Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 10 Jun 2014 20:17:37 -0700 Subject: #171 Add ability to change email, email/password to UserFragment --- res/drawable-hdpi/ic_menu_password_dark.png | Bin 0 -> 843 bytes res/drawable-hdpi/ic_menu_password_light.png | Bin 0 -> 958 bytes res/drawable-mdpi/ic_menu_password_dark.png | Bin 0 -> 554 bytes res/drawable-mdpi/ic_menu_password_light.png | Bin 0 -> 676 bytes res/drawable-xhdpi/ic_menu_password_dark.png | Bin 0 -> 1067 bytes res/drawable-xhdpi/ic_menu_password_light.png | Bin 0 -> 1234 bytes res/drawable-xxhdpi/ic_menu_password_dark.png | Bin 0 -> 1610 bytes res/drawable-xxhdpi/ic_menu_password_light.png | Bin 0 -> 1852 bytes res/layout/change_email.xml | 28 ++++ res/menu/admin_context.xml | 4 + res/menu/user.xml | 10 ++ res/menu/user_user.xml | 14 ++ res/values/attrs.xml | 1 + res/values/strings.xml | 5 + res/values/themes.xml | 3 + .../daneren2005/dsub/fragments/AdminFragment.java | 98 +---------- .../daneren2005/dsub/fragments/UserFragment.java | 58 +++---- .../dsub/service/CachedMusicService.java | 9 + .../daneren2005/dsub/service/MusicService.java | 2 + .../dsub/service/OfflineMusicService.java | 5 + .../daneren2005/dsub/service/RESTMusicService.java | 10 ++ src/github/daneren2005/dsub/util/UserUtil.java | 184 ++++++++++++++++++++- 22 files changed, 302 insertions(+), 129 deletions(-) create mode 100644 res/drawable-hdpi/ic_menu_password_dark.png create mode 100644 res/drawable-hdpi/ic_menu_password_light.png create mode 100644 res/drawable-mdpi/ic_menu_password_dark.png create mode 100644 res/drawable-mdpi/ic_menu_password_light.png create mode 100644 res/drawable-xhdpi/ic_menu_password_dark.png create mode 100644 res/drawable-xhdpi/ic_menu_password_light.png create mode 100644 res/drawable-xxhdpi/ic_menu_password_dark.png create mode 100644 res/drawable-xxhdpi/ic_menu_password_light.png create mode 100644 res/layout/change_email.xml create mode 100644 res/menu/user_user.xml (limited to 'src') diff --git a/res/drawable-hdpi/ic_menu_password_dark.png b/res/drawable-hdpi/ic_menu_password_dark.png new file mode 100644 index 00000000..67fa3e84 Binary files /dev/null and b/res/drawable-hdpi/ic_menu_password_dark.png differ diff --git a/res/drawable-hdpi/ic_menu_password_light.png b/res/drawable-hdpi/ic_menu_password_light.png new file mode 100644 index 00000000..bd99c01f Binary files /dev/null and b/res/drawable-hdpi/ic_menu_password_light.png differ diff --git a/res/drawable-mdpi/ic_menu_password_dark.png b/res/drawable-mdpi/ic_menu_password_dark.png new file mode 100644 index 00000000..74d0095a Binary files /dev/null and b/res/drawable-mdpi/ic_menu_password_dark.png differ diff --git a/res/drawable-mdpi/ic_menu_password_light.png b/res/drawable-mdpi/ic_menu_password_light.png new file mode 100644 index 00000000..159f7889 Binary files /dev/null and b/res/drawable-mdpi/ic_menu_password_light.png differ diff --git a/res/drawable-xhdpi/ic_menu_password_dark.png b/res/drawable-xhdpi/ic_menu_password_dark.png new file mode 100644 index 00000000..d1fc0a97 Binary files /dev/null and b/res/drawable-xhdpi/ic_menu_password_dark.png differ diff --git a/res/drawable-xhdpi/ic_menu_password_light.png b/res/drawable-xhdpi/ic_menu_password_light.png new file mode 100644 index 00000000..1cbf085c Binary files /dev/null and b/res/drawable-xhdpi/ic_menu_password_light.png differ diff --git a/res/drawable-xxhdpi/ic_menu_password_dark.png b/res/drawable-xxhdpi/ic_menu_password_dark.png new file mode 100644 index 00000000..a7cd1a6d Binary files /dev/null and b/res/drawable-xxhdpi/ic_menu_password_dark.png differ diff --git a/res/drawable-xxhdpi/ic_menu_password_light.png b/res/drawable-xxhdpi/ic_menu_password_light.png new file mode 100644 index 00000000..5670a209 Binary files /dev/null and b/res/drawable-xxhdpi/ic_menu_password_light.png differ diff --git a/res/layout/change_email.xml b/res/layout/change_email.xml new file mode 100644 index 00000000..8b74215c --- /dev/null +++ b/res/layout/change_email.xml @@ -0,0 +1,28 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/menu/admin_context.xml b/res/menu/admin_context.xml index 8cd04859..922a24a9 100644 --- a/res/menu/admin_context.xml +++ b/res/menu/admin_context.xml @@ -2,6 +2,10 @@ + + diff --git a/res/menu/user.xml b/res/menu/user.xml index ace011b1..aea881fc 100644 --- a/res/menu/user.xml +++ b/res/menu/user.xml @@ -8,6 +8,16 @@ android:icon="?attr/save" compat:showAsAction="always|withText"/> + + + + diff --git a/res/menu/user_user.xml b/res/menu/user_user.xml new file mode 100644 index 00000000..f66aa793 --- /dev/null +++ b/res/menu/user_user.xml @@ -0,0 +1,14 @@ + + + + + + + \ No newline at end of file diff --git a/res/values/attrs.xml b/res/values/attrs.xml index b820c371..ac535487 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -22,5 +22,6 @@ + diff --git a/res/values/strings.xml b/res/values/strings.xml index 460e46db..d43d8c7b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -450,6 +450,11 @@ Update Permissions Successfully updated permission for %1$s Failed to update permissions for %1$s + Change Email + Successfully changed email for %1$s + Failed to change email for %1$s + New Email: + Enter a valid email Change Password Successfully changed password for %1$s Failed to change password for %1$s diff --git a/res/values/themes.xml b/res/values/themes.xml index 0f464baa..6611cff7 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -25,6 +25,7 @@ @drawable/ic_menu_bookmark_light @drawable/ic_menu_share_light @drawable/ic_menu_add_person_light + @drawable/ic_menu_password_light @array/drawerItemIconsLight @style/DSub.TextViewStyle @style/DSub.ButtonStyle.Light @@ -55,6 +56,7 @@ @drawable/ic_menu_bookmark_dark @drawable/ic_menu_share_dark @drawable/ic_menu_add_person_dark + @drawable/ic_menu_password_dark @array/drawerItemIconsDark @style/DSub.TextViewStyle @style/DSub.ButtonStyle.Dark @@ -88,6 +90,7 @@ @drawable/ic_menu_bookmark_dark @drawable/ic_menu_share_dark @drawable/ic_menu_add_person_dark + @drawable/ic_menu_password_dark @array/drawerItemIconsDark @style/DSub.TextViewStyle @style/DSub.ButtonStyle.Dark diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java index b7f09532..e0989e43 100644 --- a/src/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/src/github/daneren2005/dsub/fragments/AdminFragment.java @@ -53,7 +53,7 @@ public class AdminFragment extends SelectListFragment { super.onCreateContextMenu(menu, view, menuInfo); MenuInflater inflater = context.getMenuInflater(); - if(UserUtil.isCurrentAdmin(context) && Util.checkServerVersion(context, "1.10")) { + if(UserUtil.isCurrentAdmin()) { inflater.inflate(R.menu.admin_context, menu); } else { inflater.inflate(R.menu.admin_context_user, menu); @@ -66,11 +66,14 @@ public class AdminFragment extends SelectListFragment { User user = objects.get(info.position); switch(menuItem.getItemId()) { + case R.id.admin_change_email: + UserUtil.changeEmail(context, user); + break; case R.id.admin_change_password: - changePassword(user); + UserUtil.changePassword(context, user); break; case R.id.admin_delete_user: - deleteUser(user); + UserUtil.deleteUser(context, user, adapter); break; } @@ -79,7 +82,7 @@ public class AdminFragment extends SelectListFragment { @Override public int getOptionsMenu() { - if(UserUtil.isCurrentAdmin(context)) { + if(UserUtil.isCurrentAdmin()) { return R.menu.admin; } else { return R.menu.empty; @@ -125,91 +128,4 @@ public class AdminFragment extends SelectListFragment { replaceFragment(fragment); } - - private void changePassword(final User user) { - View layout = context.getLayoutInflater().inflate(R.layout.change_password, null); - final TextView passwordView = (TextView) layout.findViewById(R.id.new_password); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.admin_change_password) - .setView(layout) - .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - final String password = passwordView.getText().toString(); - // Don't allow blank passwords - if ("".equals(password)) { - Util.toast(context, R.string.admin_change_password_invalid); - return; - } - - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.changePassword(user.getUsername(), password, context, null); - return null; - } - - @Override - protected void done(Void v) { - Util.toast(context, context.getResources().getString(R.string.admin_change_password_success, user.getUsername())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.admin_change_password_error, user.getUsername()); - } - - Util.toast(context, msg); - } - }.execute(); - } - }) - .setNegativeButton(R.string.common_cancel, null) - .setCancelable(true); - - AlertDialog dialog = builder.create(); - dialog.show(); - } - - private void deleteUser(final User user) { - Util.confirmDialog(context, R.string.common_delete, user.getUsername(), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.deleteUser(user.getUsername(), context, null); - return null; - } - - @Override - protected void done(Void v) { - adapter.remove(user); - adapter.notifyDataSetChanged(); - - Util.toast(context, context.getResources().getString(R.string.admin_delete_user_success, user.getUsername())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.admin_delete_user_error, user.getUsername()); - } - - Util.toast(context, msg); - } - }.execute(); - } - }); - } } diff --git a/src/github/daneren2005/dsub/fragments/UserFragment.java b/src/github/daneren2005/dsub/fragments/UserFragment.java index f2af85fb..6423ebcd 100644 --- a/src/github/daneren2005/dsub/fragments/UserFragment.java +++ b/src/github/daneren2005/dsub/fragments/UserFragment.java @@ -15,6 +15,9 @@ package github.daneren2005.dsub.fragments; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.os.Bundle; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; @@ -24,8 +27,10 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; +import android.widget.TextView; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.activity.SubsonicActivity; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; @@ -39,12 +44,10 @@ import github.daneren2005.dsub.view.SettingsAdapter; public class UserFragment extends SubsonicFragment{ private ListView listView; - private LayoutInflater inflater; private User user; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - this.inflater = inflater; rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); @@ -54,23 +57,30 @@ public class UserFragment extends SubsonicFragment{ user = (User) args.getSerializable(Constants.INTENT_EXTRA_NAME_ID); listView = (ListView)rootView.findViewById(R.id.fragment_list); - listView.setAdapter(new SettingsAdapter(context, user.getSettings(), UserUtil.isCurrentAdmin(context))); + listView.setAdapter(new SettingsAdapter(context, user.getSettings(), UserUtil.isCurrentAdmin())); setTitle(user.getUsername()); return rootView; } + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + activity.invalidateOptionsMenu(); + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - if(!primaryFragment) { + // For some reason this is called before onAttach + if(!primaryFragment || context == null) { return; } - if(UserUtil.isCurrentAdmin(context)) { + if(UserUtil.isCurrentAdmin() && Util.checkServerVersion(context, "1.10")) { menuInflater.inflate(R.menu.user, menu); } else { - menuInflater.inflate(R.menu.empty, menu); + menuInflater.inflate(R.menu.user_user, menu); } } @@ -82,38 +92,16 @@ public class UserFragment extends SubsonicFragment{ switch (item.getItemId()) { case R.id.menu_update_permissions: - updateSettings(); + UserUtil.updateSettings(context, user); + return true; + case R.id.menu_change_password: + UserUtil.changePassword(context, user); + return true; + case R.id.menu_change_email: + UserUtil.changeEmail(context, user); return true; } return false; } - - private void updateSettings() { - new SilentBackgroundTask(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - musicService.updateUser(user, context, null); - return null; - } - - @Override - protected void done(Void v) { - Util.toast(context, context.getResources().getString(R.string.admin_update_permissions_success, user.getUsername())); - } - - @Override - protected void error(Throwable error) { - String msg; - if (error instanceof OfflineException || error instanceof ServerTooOldException) { - msg = getErrorMessage(error); - } else { - msg = context.getResources().getString(R.string.admin_update_permissions_error, user.getUsername()); - } - - Util.toast(context, msg); - } - }.execute(); - } } diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index 86289511..0049e0ac 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -562,6 +562,15 @@ public class CachedMusicService implements MusicService { file.delete(); } + @Override + public void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception { + musicService.changeEmail(username, email, context, progressListener); + + // Delete cached users if any have been removed from list + File file = new File(context.getCacheDir(), getCacheName(context, "users")); + file.delete(); + } + @Override public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { musicService.changePassword(username, password, context, progressListener); diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java index 6f58603c..dc760f86 100644 --- a/src/github/daneren2005/dsub/service/MusicService.java +++ b/src/github/daneren2005/dsub/service/MusicService.java @@ -172,6 +172,8 @@ public interface MusicService { void deleteUser(String username, Context context, ProgressListener progressListener) throws Exception; + void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception; + void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception; Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception; diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java index 9e2b9e13..75a090c6 100644 --- a/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -715,6 +715,11 @@ public class OfflineMusicService extends RESTMusicService { throw new OfflineException("Deleting users not available in offline mode"); } + @Override + public void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception { + throw new OfflineException("Changing email not available in offline mode"); + } + @Override public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException("Changing passwords not available in offline mode"); diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index c2f64dad..371e309c 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -1263,6 +1263,16 @@ public class RESTMusicService implements MusicService { } } + @Override + public void changeEmail(String username, String email, Context context, ProgressListener progressListener) throws Exception { + Reader reader = getReader(context, progressListener, "updateUser", null, Arrays.asList("username", "email"), Arrays.asList(username, email)); + try { + new ErrorParser(context).parse(reader); + } finally { + Util.close(reader); + } + } + @Override public void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception { Reader reader = getReader(context, progressListener, "changePassword", null, Arrays.asList("username", "password"), Arrays.asList(username, password)); diff --git a/src/github/daneren2005/dsub/util/UserUtil.java b/src/github/daneren2005/dsub/util/UserUtil.java index 5158829c..60243731 100644 --- a/src/github/daneren2005/dsub/util/UserUtil.java +++ b/src/github/daneren2005/dsub/util/UserUtil.java @@ -15,14 +15,24 @@ package github.daneren2005.dsub.util; +import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.content.SharedPreferences; +import android.view.View; +import android.widget.Adapter; +import android.widget.ArrayAdapter; +import android.widget.TextView; import java.io.File; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.service.OfflineException; +import github.daneren2005.dsub.service.ServerTooOldException; public final class UserUtil { private static User currentUser; @@ -55,15 +65,15 @@ public final class UserUtil { return getCurrentUsername(context, Util.getActiveServer(context)); } - public static boolean isCurrentAdmin(Context context) { + public static boolean isCurrentAdmin() { if(currentUser == null) { return false; } else { - return isCurrentRole(context, "adminRole"); + return isCurrentRole("adminRole"); } } - public static boolean isCurrentRole(Context context, String role) { + public static boolean isCurrentRole(String role) { if(currentUser == null) { return false; } @@ -76,4 +86,172 @@ public final class UserUtil { return false; } + + public static void changePassword(final Activity context, final User user) { + View layout = context.getLayoutInflater().inflate(R.layout.change_password, null); + final TextView passwordView = (TextView) layout.findViewById(R.id.new_password); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.admin_change_password) + .setView(layout) + .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + final String password = passwordView.getText().toString(); + // Don't allow blank passwords + if ("".equals(password)) { + Util.toast(context, R.string.admin_change_password_invalid); + return; + } + + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.changePassword(user.getUsername(), password, context, null); + return null; + } + + @Override + protected void done(Void v) { + Util.toast(context, context.getResources().getString(R.string.admin_change_password_success, user.getUsername())); + } + + @Override + protected void error(Throwable error) { + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.admin_change_password_error, user.getUsername()); + } + + Util.toast(context, msg); + } + }.execute(); + } + }) + .setNegativeButton(R.string.common_cancel, null) + .setCancelable(true); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + public static void updateSettings(final Context context, final User user) { + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.updateUser(user, context, null); + return null; + } + + @Override + protected void done(Void v) { + Util.toast(context, context.getResources().getString(R.string.admin_update_permissions_success, user.getUsername())); + } + + @Override + protected void error(Throwable error) { + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.admin_update_permissions_error, user.getUsername()); + } + + Util.toast(context, msg); + } + }.execute(); + } + + public static void changeEmail(final Activity context, final User user) { + View layout = context.getLayoutInflater().inflate(R.layout.change_email, null); + final TextView emailView = (TextView) layout.findViewById(R.id.new_email); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.admin_change_email) + .setView(layout) + .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + final String email = emailView.getText().toString(); + // Don't allow blank emails + if ("".equals(email)) { + Util.toast(context, R.string.admin_change_email_invalid); + return; + } + + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.changeEmail(user.getUsername(), email, context, null); + return null; + } + + @Override + protected void done(Void v) { + Util.toast(context, context.getResources().getString(R.string.admin_change_email_success, user.getUsername())); + } + + @Override + protected void error(Throwable error) { + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.admin_change_email_error, user.getUsername()); + } + + Util.toast(context, msg); + } + }.execute(); + } + }) + .setNegativeButton(R.string.common_cancel, null) + .setCancelable(true); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + public static void deleteUser(final Context context, final User user, final ArrayAdapter adapter) { + Util.confirmDialog(context, R.string.common_delete, user.getUsername(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.deleteUser(user.getUsername(), context, null); + return null; + } + + @Override + protected void done(Void v) { + if(adapter != null) { + adapter.remove(user); + adapter.notifyDataSetChanged(); + } + + Util.toast(context, context.getResources().getString(R.string.admin_delete_user_success, user.getUsername())); + } + + @Override + protected void error(Throwable error) { + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.admin_delete_user_error, user.getUsername()); + } + + Util.toast(context, msg); + } + }.execute(); + } + }); + } } -- cgit v1.2.3 From feabbbf4f5919932e6446978af328dbbef2cf37f Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Tue, 10 Jun 2014 22:27:38 -0700 Subject: #171 Add avatars to Admin tab --- res/drawable-hdpi/ic_social_person.png | Bin 0 -> 4518 bytes res/drawable-mdpi/ic_social_person.png | Bin 0 -> 2834 bytes res/drawable-xhdpi/ic_social_person.png | Bin 0 -> 5960 bytes res/drawable-xxhdpi/ic_social_person.png | Bin 0 -> 9169 bytes res/layout/user_header.xml | 57 ++++++++++++++++++++ res/layout/user_list_item.xml | 45 ++++++++++++++++ .../daneren2005/dsub/fragments/AdminFragment.java | 2 +- .../daneren2005/dsub/fragments/UserFragment.java | 23 ++++++++ .../dsub/service/CachedMusicService.java | 4 +- .../daneren2005/dsub/service/MusicService.java | 2 +- .../dsub/service/OfflineMusicService.java | 2 +- .../daneren2005/dsub/service/RESTMusicService.java | 53 +++++++++++++++++- src/github/daneren2005/dsub/util/FileUtil.java | 28 ++++++++++ src/github/daneren2005/dsub/util/ImageLoader.java | 59 +++++++++++++++++++-- src/github/daneren2005/dsub/view/UserAdapter.java | 7 ++- src/github/daneren2005/dsub/view/UserView.java | 14 +++-- 16 files changed, 277 insertions(+), 19 deletions(-) create mode 100644 res/drawable-hdpi/ic_social_person.png create mode 100644 res/drawable-mdpi/ic_social_person.png create mode 100644 res/drawable-xhdpi/ic_social_person.png create mode 100644 res/drawable-xxhdpi/ic_social_person.png create mode 100644 res/layout/user_header.xml create mode 100644 res/layout/user_list_item.xml (limited to 'src') diff --git a/res/drawable-hdpi/ic_social_person.png b/res/drawable-hdpi/ic_social_person.png new file mode 100644 index 00000000..0a0a5ff2 Binary files /dev/null and b/res/drawable-hdpi/ic_social_person.png differ diff --git a/res/drawable-mdpi/ic_social_person.png b/res/drawable-mdpi/ic_social_person.png new file mode 100644 index 00000000..c09313d8 Binary files /dev/null and b/res/drawable-mdpi/ic_social_person.png differ diff --git a/res/drawable-xhdpi/ic_social_person.png b/res/drawable-xhdpi/ic_social_person.png new file mode 100644 index 00000000..ed333afe Binary files /dev/null and b/res/drawable-xhdpi/ic_social_person.png differ diff --git a/res/drawable-xxhdpi/ic_social_person.png b/res/drawable-xxhdpi/ic_social_person.png new file mode 100644 index 00000000..f81dc6a4 Binary files /dev/null and b/res/drawable-xxhdpi/ic_social_person.png differ diff --git a/res/layout/user_header.xml b/res/layout/user_header.xml new file mode 100644 index 00000000..5966e0ed --- /dev/null +++ b/res/layout/user_header.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/layout/user_list_item.xml b/res/layout/user_list_item.xml new file mode 100644 index 00000000..40dcf06d --- /dev/null +++ b/res/layout/user_list_item.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java index e0989e43..216ac000 100644 --- a/src/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/src/github/daneren2005/dsub/fragments/AdminFragment.java @@ -91,7 +91,7 @@ public class AdminFragment extends SelectListFragment { @Override public ArrayAdapter getAdapter(List objs) { - return new UserAdapter(context, objs); + return new UserAdapter(context, objs, getImageLoader()); } @Override diff --git a/src/github/daneren2005/dsub/fragments/UserFragment.java b/src/github/daneren2005/dsub/fragments/UserFragment.java index 6423ebcd..fbd672c0 100644 --- a/src/github/daneren2005/dsub/fragments/UserFragment.java +++ b/src/github/daneren2005/dsub/fragments/UserFragment.java @@ -26,6 +26,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; @@ -37,6 +38,7 @@ import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.service.OfflineException; import github.daneren2005.dsub.service.ServerTooOldException; import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.ImageLoader; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; @@ -57,6 +59,7 @@ public class UserFragment extends SubsonicFragment{ user = (User) args.getSerializable(Constants.INTENT_EXTRA_NAME_ID); listView = (ListView)rootView.findViewById(R.id.fragment_list); + createHeader(); listView.setAdapter(new SettingsAdapter(context, user.getSettings(), UserUtil.isCurrentAdmin())); setTitle(user.getUsername()); @@ -104,4 +107,24 @@ public class UserFragment extends SubsonicFragment{ return false; } + + private void createHeader() { + View header = LayoutInflater.from(context).inflate(R.layout.user_header, listView, false); + + final ImageLoader imageLoader = getImageLoader(); + ImageView coverArtView = (ImageView) header.findViewById(R.id.user_avatar); + imageLoader.loadAvatar(context, coverArtView, user.getUsername()); + + TextView usernameView = (TextView) header.findViewById(R.id.user_username); + usernameView.setText(user.getUsername()); + + final TextView emailView = (TextView) header.findViewById(R.id.user_email); + if(user.getEmail() != null) { + emailView.setText(user.getEmail()); + } else { + emailView.setVisibility(View.GONE); + } + + listView.addHeaderView(header); + } } diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index 0049e0ac..bd43fbed 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -577,8 +577,8 @@ public class CachedMusicService implements MusicService { } @Override - public Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception { - return musicService.getAvatar(username, context, progressListener); + public Bitmap getAvatar(String username, int size, Context context, ProgressListener progressListener) throws Exception { + return musicService.getAvatar(username, size, context, progressListener); } @Override diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java index dc760f86..cefd0c23 100644 --- a/src/github/daneren2005/dsub/service/MusicService.java +++ b/src/github/daneren2005/dsub/service/MusicService.java @@ -176,7 +176,7 @@ public interface MusicService { void changePassword(String username, String password, Context context, ProgressListener progressListener) throws Exception; - Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception; + Bitmap getAvatar(String username, int size, Context context, ProgressListener progressListener) throws Exception; int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception; diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java index 75a090c6..a92e41d1 100644 --- a/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -726,7 +726,7 @@ public class OfflineMusicService extends RESTMusicService { } @Override - public Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception { + public Bitmap getAvatar(String username, int size, Context context, ProgressListener progressListener) throws Exception { return null; } diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index 371e309c..11431eaa 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -1284,8 +1284,57 @@ public class RESTMusicService implements MusicService { } @Override - public Bitmap getAvatar(String username, Context context, ProgressListener progressListener) throws Exception { - return null; + public Bitmap getAvatar(String username, int size, Context context, ProgressListener progressListener) throws Exception { + // Return silently if server is too old + if (!Util.checkServerVersion(context, "1.8")) { + return null; + } + + // Synchronize on the username so that we don't download concurrently for + // the same user. + synchronized (username) { + // Use cached file, if existing. + Bitmap bitmap = FileUtil.getAvatarBitmap(context, username, size); + if(bitmap != null) { + return bitmap; + } + + String url = Util.getRestUrl(context, "getAvatar"); + InputStream in = null; + try + { + List parameterNames; + List parameterValues; + + parameterNames = Collections.singletonList("username"); + parameterValues = Arrays.asList(username); + + HttpEntity entity = getEntityForURL(context, url, null, parameterNames, parameterValues, progressListener); + in = entity.getContent(); + + // If content type is XML, an error occurred. Get it. + String contentType = Util.getContentType(entity); + if (contentType != null && contentType.startsWith("text/xml")) + { + new ErrorParser(context).parse(new InputStreamReader(in, Constants.UTF_8)); + return null; // Never reached. + } + + byte[] bytes = Util.toByteArray(in); + OutputStream out = null; + try { + out = new FileOutputStream(FileUtil.getAvatarFile(context, username)); + out.write(bytes); + } finally { + Util.close(out); + } + + return FileUtil.getSampledBitmap(bytes, size); + } + finally { + Util.close(in); + } + } } @Override diff --git a/src/github/daneren2005/dsub/util/FileUtil.java b/src/github/daneren2005/dsub/util/FileUtil.java index a68ded45..e84f6eb2 100644 --- a/src/github/daneren2005/dsub/util/FileUtil.java +++ b/src/github/daneren2005/dsub/util/FileUtil.java @@ -200,6 +200,34 @@ public class FileUtil { } return null; } + + public static File getAvatarDirectory(Context context) { + File avatarDir = new File(getSubsonicDirectory(context), "avatars"); + ensureDirectoryExistsAndIsReadWritable(avatarDir); + ensureDirectoryExistsAndIsReadWritable(new File(avatarDir, ".nomedia")); + return avatarDir; + } + + public static File getAvatarFile(Context context, String username) { + return new File(getAvatarDirectory(context), Util.md5Hex(username) + ".jpeg"); + } + + public static Bitmap getAvatarBitmap(Context context, String username, int size) { + File avatarFile = getAvatarFile(context, username); + if (avatarFile.exists()) { + final BitmapFactory.Options opt = new BitmapFactory.Options(); + opt.inJustDecodeBounds = true; + BitmapFactory.decodeFile(avatarFile.getPath(), opt); + opt.inPurgeable = true; + opt.inSampleSize = Util.calculateInSampleSize(opt, size, Util.getScaledHeight(opt.outHeight, opt.outWidth, size)); + opt.inJustDecodeBounds = false; + + Bitmap bitmap = BitmapFactory.decodeFile(avatarFile.getPath(), opt); + return bitmap == null ? null : getScaledBitmap(bitmap, size); + } + return null; + } + public static Bitmap getSampledBitmap(byte[] bytes, int size) { final BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inJustDecodeBounds = true; diff --git a/src/github/daneren2005/dsub/util/ImageLoader.java b/src/github/daneren2005/dsub/util/ImageLoader.java index b1b00cc5..f9c5fed5 100644 --- a/src/github/daneren2005/dsub/util/ImageLoader.java +++ b/src/github/daneren2005/dsub/util/ImageLoader.java @@ -18,7 +18,6 @@ */ package github.daneren2005.dsub.util; -import android.annotation.TargetApi; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; @@ -26,7 +25,6 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.TransitionDrawable; import android.media.RemoteControlClient; import android.os.Build; -import android.os.Handler; import android.util.DisplayMetrics; import android.util.Log; import android.support.v4.util.LruCache; @@ -38,9 +36,6 @@ import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - /** * Asynchronous loading of images, with caching. *

@@ -56,6 +51,7 @@ public class ImageLoader { private Bitmap nowPlaying; private final int imageSizeDefault; private final int imageSizeLarge; + private final int avatarSizeDefault; private Drawable largeUnknownImage; public ImageLoader(Context context) { @@ -86,6 +82,7 @@ public class ImageLoader { imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight(); DisplayMetrics metrics = context.getResources().getDisplayMetrics(); imageSizeLarge = Math.round(Math.min(metrics.widthPixels, metrics.heightPixels)); + avatarSizeDefault = context.getResources().getDrawable(R.drawable.ic_social_person).getIntrinsicHeight(); createLargeUnknownImage(context); } @@ -173,6 +170,17 @@ public class ImageLoader { new RemoteControlClientImageTask(context, entry, imageSizeLarge, imageSizeLarge, false, remoteControl).execute(); } + public void loadAvatar(Context context, ImageView view, String username) { + Bitmap bitmap = cache.get(username); + if (bitmap != null && !bitmap.isRecycled()) { + Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); + view.setImageDrawable(drawable); + return; + } + + new AvatarTask(context, view, username).execute(); + } + private String getKey(String coverArtId, int size) { return coverArtId + size; } @@ -322,4 +330,45 @@ public class ImageLoader { setImage(mRemoteControl, mDrawable); } } + + private class AvatarTask extends SilentBackgroundTask { + private final Context mContext; + private final String mUsername; + private final ImageView mView; + private Drawable mDrawable; + + public AvatarTask(Context context, ImageView view, String username) { + super(context); + mContext = context; + mView = view; + mUsername = username; + } + + @Override + protected Void doInBackground() throws Throwable { + try { + MusicService musicService = MusicServiceFactory.getMusicService(mContext); + Bitmap bitmap = musicService.getAvatar(mUsername, avatarSizeDefault, mContext, null); + if(bitmap != null) { + cache.put(mUsername, bitmap); + // Make sure key is the most recently "used" + cache.get(mUsername); + + mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); + } + } catch (Throwable x) { + Log.e(TAG, "Failed to download album art.", x); + cancelled = true; + } + + return null; + } + + @Override + protected void done(Void result) { + if(mDrawable != null) { + mView.setImageDrawable(mDrawable); + } + } + } } diff --git a/src/github/daneren2005/dsub/view/UserAdapter.java b/src/github/daneren2005/dsub/view/UserAdapter.java index 937e2e92..70a1748a 100644 --- a/src/github/daneren2005/dsub/view/UserAdapter.java +++ b/src/github/daneren2005/dsub/view/UserAdapter.java @@ -24,13 +24,16 @@ import java.util.List; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.util.ImageLoader; public class UserAdapter extends ArrayAdapter { private final Context activity; + private final ImageLoader imageLoader; - public UserAdapter(Context activity, List users) { + public UserAdapter(Context activity, List users, ImageLoader imageLoader) { super(activity, R.layout.basic_list_item, users); this.activity = activity; + this.imageLoader = imageLoader; } @Override @@ -42,7 +45,7 @@ public class UserAdapter extends ArrayAdapter { } else { view = new UserView(activity); } - view.setObject(entry); + view.setObject(entry, imageLoader); return view; } } \ No newline at end of file diff --git a/src/github/daneren2005/dsub/view/UserView.java b/src/github/daneren2005/dsub/view/UserView.java index f966f28f..31e02d99 100644 --- a/src/github/daneren2005/dsub/view/UserView.java +++ b/src/github/daneren2005/dsub/view/UserView.java @@ -23,18 +23,21 @@ import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.util.ImageLoader; public class UserView extends UpdateView { private User user; - private TextView userNameView; + private TextView usernameView; + private ImageView avatarView; public UserView(Context context) { super(context); this.context = context; - LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); + LayoutInflater.from(context).inflate(R.layout.user_list_item, this, true); - userNameView = (TextView) findViewById(R.id.item_name); + usernameView = (TextView) findViewById(R.id.item_name); + avatarView = (ImageView) findViewById(R.id.item_avatar); moreButton = (ImageView) findViewById(R.id.item_more); moreButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { @@ -43,8 +46,9 @@ public class UserView extends UpdateView { }); } - protected void setObjectImpl(Object obj) { + protected void setObjectImpl(Object obj, Object obj2) { this.user = (User) obj; - userNameView.setText(user.getUsername()); + usernameView.setText(user.getUsername()); + ((ImageLoader)obj2).loadAvatar(context, avatarView, user.getUsername()); } } -- cgit v1.2.3 From 3fc67575b4047005482321c940429cc4eb420a12 Mon Sep 17 00:00:00 2001 From: Scott Jackson Date: Wed, 11 Jun 2014 17:40:36 -0700 Subject: #171 Add create user dialog --- res/layout/create_user.xml | 77 +++++++++++++++++++ res/values/strings.xml | 6 ++ .../daneren2005/dsub/fragments/AdminFragment.java | 15 ++++ .../daneren2005/dsub/service/RESTMusicService.java | 17 ++++- src/github/daneren2005/dsub/util/UserUtil.java | 88 ++++++++++++++++++++++ .../daneren2005/dsub/view/SettingsAdapter.java | 7 ++ 6 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 res/layout/create_user.xml (limited to 'src') diff --git a/res/layout/create_user.xml b/res/layout/create_user.xml new file mode 100644 index 00000000..4d918fc9 --- /dev/null +++ b/res/layout/create_user.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index d43d8c7b..4957587b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -447,6 +447,12 @@ Share via Delete Share + Username: + Email: + Password: + Successfully created new user + Failed to create new user + Enter a valid username Update Permissions Successfully updated permission for %1$s Failed to update permissions for %1$s diff --git a/src/github/daneren2005/dsub/fragments/AdminFragment.java b/src/github/daneren2005/dsub/fragments/AdminFragment.java index 216ac000..19aa4b95 100644 --- a/src/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/src/github/daneren2005/dsub/fragments/AdminFragment.java @@ -48,6 +48,21 @@ import github.daneren2005.dsub.view.UserAdapter; public class AdminFragment extends SelectListFragment { private static String TAG = AdminFragment.class.getSimpleName(); + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if(super.onOptionsItemSelected(item)) { + return true; + } + + switch (item.getItemId()) { + case R.id.menu_add_user: + UserUtil.addNewUser(context, this); + break; + } + + return false; + } + @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, view, menuInfo); diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index 11431eaa..3299ec4b 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -1220,7 +1220,22 @@ public class RESTMusicService implements MusicService { @Override public void createUser(User user, Context context, ProgressListener progressListener) throws Exception { - Reader reader = getReader(context, progressListener, "createUser", null); + List names = new ArrayList(); + List values = new ArrayList(); + + names.add("username"); + values.add(user.getUsername()); + names.add("email"); + values.add(user.getEmail()); + names.add("password"); + values.add(user.getPassword()); + + for(User.Setting setting: user.getSettings()) { + names.add(setting.getName()); + values.add(setting.getValue()); + } + + Reader reader = getReader(context, progressListener, "createUser", null, names, values); try { new ErrorParser(context).parse(reader); } finally { diff --git a/src/github/daneren2005/dsub/util/UserUtil.java b/src/github/daneren2005/dsub/util/UserUtil.java index 60243731..3e6d9ce7 100644 --- a/src/github/daneren2005/dsub/util/UserUtil.java +++ b/src/github/daneren2005/dsub/util/UserUtil.java @@ -23,16 +23,19 @@ import android.content.SharedPreferences; import android.view.View; import android.widget.Adapter; import android.widget.ArrayAdapter; +import android.widget.ListView; import android.widget.TextView; import java.io.File; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.fragments.SubsonicFragment; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.service.OfflineException; import github.daneren2005.dsub.service.ServerTooOldException; +import github.daneren2005.dsub.view.SettingsAdapter; public final class UserUtil { private static User currentUser; @@ -254,4 +257,89 @@ public final class UserUtil { } }); } + + public static void addNewUser(final Activity context, final SubsonicFragment fragment) { + final User user = new User(); + user.addSetting("adminRole", false); + user.addSetting("settingsRole", true); + user.addSetting("downloadRole", false); + user.addSetting("uploadRole", false); + user.addSetting("coverArtRole", false); + user.addSetting("commentRole", false); + user.addSetting("podcastRole", false); + user.addSetting("streamRole", true); + user.addSetting("jukeboxRole", false); + user.addSetting("shareRole", false); + + View layout = context.getLayoutInflater().inflate(R.layout.create_user, null); + final TextView usernameView = (TextView) layout.findViewById(R.id.username); + final TextView emailView = (TextView) layout.findViewById(R.id.email); + final TextView passwordView = (TextView) layout.findViewById(R.id.password); + final ListView listView = (ListView) layout.findViewById(R.id.settings_list); + listView.setAdapter(new SettingsAdapter(context, user, true)); + + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.menu_add_user) + .setView(layout) + .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + final String username = usernameView.getText().toString(); + // Don't allow blank emails + if ("".equals(username)) { + Util.toast(context, R.string.admin_change_username_invalid); + return; + } + + final String email = emailView.getText().toString(); + // Don't allow blank emails + if ("".equals(email)) { + Util.toast(context, R.string.admin_change_email_invalid); + return; + } + + final String password = passwordView.getText().toString(); + if ("".equals(password)) { + Util.toast(context, R.string.admin_change_password_invalid); + return; + } + + user.setUsername(username); + user.setEmail(email); + user.setPassword(password); + + new SilentBackgroundTask(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + musicService.createUser(user, context, null); + return null; + } + + @Override + protected void done(Void v) { + fragment.onRefresh(); + Util.toast(context, context.getResources().getString(R.string.admin_create_user_success)); + } + + @Override + protected void error(Throwable error) { + String msg; + if (error instanceof OfflineException || error instanceof ServerTooOldException) { + msg = getErrorMessage(error); + } else { + msg = context.getResources().getString(R.string.admin_create_user_error); + } + + Util.toast(context, msg); + } + }.execute(); + } + }) + .setNegativeButton(R.string.common_cancel, null) + .setCancelable(true); + + AlertDialog dialog = builder.create(); + dialog.show(); + } } diff --git a/src/github/daneren2005/dsub/view/SettingsAdapter.java b/src/github/daneren2005/dsub/view/SettingsAdapter.java index 88019c00..ce6c12ed 100644 --- a/src/github/daneren2005/dsub/view/SettingsAdapter.java +++ b/src/github/daneren2005/dsub/view/SettingsAdapter.java @@ -23,6 +23,7 @@ import android.widget.ArrayAdapter; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.User; import static github.daneren2005.dsub.domain.User.Setting; @@ -30,6 +31,12 @@ public class SettingsAdapter extends ArrayAdapter { private final Context context; private final boolean editable; + public SettingsAdapter(Context context, User user, boolean editable) { + super(context, R.layout.basic_list_item, user.getSettings()); + this.context = context; + this.editable = editable; + } + public SettingsAdapter(Context context, List settings, boolean editable) { super(context, R.layout.basic_list_item, settings); this.context = context; -- cgit v1.2.3