From 659646390ee980ac615f36585ddddee28c0526e4 Mon Sep 17 00:00:00 2001 From: Kazuki Yamaguchi Date: Thu, 1 Oct 2015 22:40:25 +0900 Subject: ☆マルチアカウント対応☆ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 8 +- .../smileessence/activity/MainActivity.java | 111 ++++++----- .../activity/ManageAccountsActivity.java | 218 +++++++++++++++++++++ .../smileessence/activity/OAuthActivity.java | 8 +- .../net/lacolaco/smileessence/entity/Account.java | 130 ++++++++---- .../net/lacolaco/smileessence/entity/RBinding.java | 13 ++ .../java/net/lacolaco/smileessence/entity/RO.java | 13 -- .../net/lacolaco/smileessence/entity/Tweet.java | 10 +- .../net/lacolaco/smileessence/entity/User.java | 4 +- .../lacolaco/smileessence/util/UIObservable.java | 6 +- .../net/lacolaco/smileessence/util/UIObserver.java | 4 +- .../smileessence/view/SettingFragment.java | 20 +- .../view/dialog/StatusDetailDialogFragment.java | 6 +- .../view/dialog/UserDetailDialogFragment.java | 6 +- .../smileessence/viewmodel/EventViewModel.java | 4 +- .../smileessence/viewmodel/MessageViewModel.java | 4 +- .../smileessence/viewmodel/StatusViewModel.java | 6 +- app/src/main/res/layout/layout_edit_list.xml | 4 +- app/src/main/res/layout/layout_license.xml | 4 +- app/src/main/res/layout/layout_main.xml | 19 +- app/src/main/res/layout/layout_oauth.xml | 84 ++++---- app/src/main/res/layout/layout_setting.xml | 4 +- app/src/main/res/menu/main.xml | 3 + app/src/main/res/values-ja/strings.xml | 7 +- app/src/main/res/values/keys.xml | 2 +- app/src/main/res/values/strings.xml | 9 +- app/src/main/res/values/styles.xml | 6 + app/src/main/res/xml/setting.xml | 12 +- 28 files changed, 529 insertions(+), 196 deletions(-) create mode 100644 app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.java create mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/RBinding.java delete mode 100644 app/src/main/java/net/lacolaco/smileessence/entity/RO.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 37e9ae00..34850971 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -109,6 +109,11 @@ android:configChanges="keyboardHidden|orientation" android:label="@string/activity_edit_template" android:parentActivityName="net.lacolaco.smileessence.activity.MainActivity" /> + + android:label="@string/activity_authenticate" + android:parentActivityName=".activity.ManageAccountsActivity" /> diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.java index 25a498e1..ce849742 100644 --- a/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.java +++ b/app/src/main/java/net/lacolaco/smileessence/activity/MainActivity.java @@ -36,22 +36,23 @@ import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.WindowManager; +import android.widget.TextView; +import com.android.volley.toolbox.NetworkImageView; import net.lacolaco.smileessence.Application; import net.lacolaco.smileessence.BuildConfig; import net.lacolaco.smileessence.IntentRouter; import net.lacolaco.smileessence.R; import net.lacolaco.smileessence.command.CommandOpenURL; +import net.lacolaco.smileessence.data.ImageCache; import net.lacolaco.smileessence.data.PostState; -import net.lacolaco.smileessence.entity.Account; -import net.lacolaco.smileessence.entity.CommandSetting; -import net.lacolaco.smileessence.entity.MuteUserIds; +import net.lacolaco.smileessence.entity.*; import net.lacolaco.smileessence.logging.Logger; import net.lacolaco.smileessence.notification.NotificationType; import net.lacolaco.smileessence.notification.Notificator; import net.lacolaco.smileessence.preference.InternalPreferenceHelper; import net.lacolaco.smileessence.preference.UserPreferenceHelper; -import net.lacolaco.smileessence.twitter.OAuthSession; import net.lacolaco.smileessence.twitter.UserStreamListener; +import net.lacolaco.smileessence.twitter.task.ShowUserTask; import net.lacolaco.smileessence.util.BitmapOptimizer; import net.lacolaco.smileessence.util.NetworkHelper; import net.lacolaco.smileessence.util.UIHandler; @@ -64,14 +65,15 @@ public class MainActivity extends AppCompatActivity { // ------------------------------ FIELDS ------------------------------ - public static final int REQUEST_OAUTH = 10; public static final int REQUEST_GET_PICTURE_FROM_GALLERY = 11; public static final int REQUEST_GET_PICTURE_FROM_CAMERA = 12; + private static final int REQUEST_MANAGE_ACCOUNT = 13; private ViewPager viewPager; private PageListAdapter pagerAdapter; private TwitterStream stream; private Uri cameraTempFilePath; private UserStreamListener userStreamListener; + private boolean waitingAccount = true; public Uri getCameraTempFilePath() { return cameraTempFilePath; @@ -134,8 +136,12 @@ public class MainActivity extends AppCompatActivity { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { - case REQUEST_OAUTH: { - receiveOAuth(requestCode, resultCode, data); + case REQUEST_MANAGE_ACCOUNT: { + if (waitingAccount) { + // first run + waitingAccount = false; + startMainLogic(); + } break; } case REQUEST_GET_PICTURE_FROM_GALLERY: @@ -154,12 +160,14 @@ public class MainActivity extends AppCompatActivity { setContentView(R.layout.layout_main); Notificator.initialize(this); CommandSetting.initialize(); + Account.load(); if (setupLastUsedAccount()) { + waitingAccount = false; startMainLogic(); IntentRouter.onNewIntent(this, getIntent()); } else { - startOAuthActivity(); + startActivityForResult(new Intent(this, ManageAccountsActivity.class), REQUEST_MANAGE_ACCOUNT); } } @@ -200,6 +208,10 @@ public class MainActivity extends AppCompatActivity { startActivity(new Intent(this, SettingActivity.class)); return true; } + case R.id.actionbar_accounts: { + startActivity(new Intent(this, ManageAccountsActivity.class)); + return true; + } case R.id.actionbar_edit_templates: { startActivity(new Intent(this, EditTemplateActivity.class)); return true; @@ -319,13 +331,11 @@ public class MainActivity extends AppCompatActivity { public void startMainLogic() { initializeView(); - startTwitter(); + onChangeCurrentAccount(); } public boolean startStream() { - if (!new NetworkHelper(this).canConnect()) { - return false; - } + if (stream != null) { stream.shutdown(); } @@ -337,26 +347,36 @@ public class MainActivity extends AppCompatActivity { return true; } - public boolean startTwitter() { - if (!startStream()) { - return false; + private void onChangeCurrentAccount() { + if (!new NetworkHelper(this).canConnect()) { + return; // TODO: error message? } - MuteUserIds.refresh(Application.getCurrentAccount()); - Application.getCurrentAccount().refreshListSubscriptions(); - updateActionBarIcon(); - return true; - } - public void updateActionBarIcon() {/* - final ImageView homeIcon = (ImageView) findViewById(android.R.id.home); - new ShowUserTask(Application.getCurrentAccount(), Application.getCurrentAccount().getUserId()) - .onDoneUI(user -> { - String urlHttps = user.getProfileImageUrl(); - homeIcon.setScaleType(ImageView.ScaleType.FIT_CENTER); - new BitmapURLTask(urlHttps, homeIcon).execute(); - }) - .onFail(x -> Notificator.getInstance().publish(R.string.notice_error_show_user, NotificationType.ALERT)) - .execute();*/ + Account account = Application.getCurrentAccount(); + User user = account.getUser(); + startStream(); + MuteUserIds.refresh(account); + account.refreshListSubscriptions(); + + getSupportActionBar().setDisplayShowTitleEnabled(false); + final TextView toolbarTitle = (TextView) findViewById(R.id.toolbar_text); + final NetworkImageView iconImageView = (NetworkImageView) findViewById(R.id.toolbar_icon); + + Runnable update = () -> { + toolbarTitle.setText(account.getUser().getScreenName()); + String oldUrl = iconImageView.getImageURL(); + String newUrl = user.getProfileImageUrl(); + if (newUrl != null && (oldUrl == null || !oldUrl.equals(newUrl))) { + ImageCache.getInstance().setImageToView(newUrl, iconImageView); + } + }; + + update.run(); + user.addObserver(this, (x, changes) -> { + if (changes.contains(RBinding.BASIC)) update.run(); + }); + + new ShowUserTask(account, account.getUserId()).execute(); } private void getImageUri(int requestCode, int resultCode, Intent data) { @@ -396,10 +416,7 @@ public class MainActivity extends AppCompatActivity { public void initializeView() { Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); - //ActionBar bar = getActionBar(); - //bar.setDisplayShowHomeEnabled(true); - //bar.setDisplayShowTitleEnabled(false); - //bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + viewPager = (ViewPager) findViewById(R.id.viewPager); pagerAdapter = new PageListAdapter(this, viewPager); initializePages(); @@ -409,28 +426,14 @@ public class MainActivity extends AppCompatActivity { setSelectedPageIndex(pagerAdapter.getIndex(UserListFragment.class)); } - private void receiveOAuth(int requestCode, int resultCode, Intent data) { - if (resultCode != RESULT_OK) { - Logger.error(requestCode); - Notificator.getInstance().publish(R.string.notice_error_authenticate); - finish(); - } else { - Account account = new Account(data.getStringExtra(OAuthSession.KEY_TOKEN), - data.getStringExtra(OAuthSession.KEY_TOKEN_SECRET), - data.getLongExtra(OAuthSession.KEY_USER_ID, -1L), - data.getStringExtra(OAuthSession.KEY_SCREEN_NAME)); - account.save(); - Application.setCurrentAccount(account); - InternalPreferenceHelper.getInstance().set(R.string.key_last_used_account_id, account.getId()); - startMainLogic(); - } - } - private boolean setupLastUsedAccount() { long lastId = InternalPreferenceHelper.getInstance().get(R.string.key_last_used_account_id, -1L); Account account = null; if (lastId != -1) { - account = Account.load(Account.class, lastId); + account = Account.get(lastId); + } + if (account == null && Account.count() > 0) { + account = Account.all().get(0); } if (account != null) { Application.setCurrentAccount(account); @@ -439,8 +442,4 @@ public class MainActivity extends AppCompatActivity { return false; } } - - private void startOAuthActivity() { - startActivityForResult(new Intent(this, OAuthActivity.class), REQUEST_OAUTH); - } } diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.java new file mode 100644 index 00000000..508c3b83 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/activity/ManageAccountsActivity.java @@ -0,0 +1,218 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2012-2014 lacolaco.net + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.lacolaco.smileessence.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.*; +import android.widget.*; +import net.lacolaco.smileessence.Application; +import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.entity.Account; +import net.lacolaco.smileessence.logging.Logger; +import net.lacolaco.smileessence.notification.Notificator; +import net.lacolaco.smileessence.preference.InternalPreferenceHelper; +import net.lacolaco.smileessence.twitter.OAuthSession; +import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment; + +import java.util.ArrayList; +import java.util.List; + +public class ManageAccountsActivity extends AppCompatActivity implements AdapterView.OnItemClickListener, AbsListView.OnItemLongClickListener { + public static final int REQUEST_OAUTH = 10; + private EditAccountsAdapter adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + setTheme(Application.getThemeResId()); + super.onCreate(savedInstanceState); + setContentView(R.layout.layout_edit_list); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + ListView listView = (ListView) findViewById(R.id.listview_edit_list); + adapter = new EditAccountsAdapter(); + listView.setAdapter(adapter); + listView.setOnItemClickListener(this); + listView.setOnItemLongClickListener(this); + + Logger.debug("onCreate"); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuItem add = menu.add(Menu.NONE, R.id.menu_edit_list_add, Menu.NONE, ""); + add.setIcon(android.R.drawable.ic_menu_add); + add.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + return true; + } + + @Override + public boolean onItemLongClick(AdapterView adapterView, View view, int i, long l) { + if (adapter.getCount() > 1) { + // remove account from application + Account account = adapter.getItem(i); + ConfirmDialogFragment.show(this, getString(R.string.dialog_confirm_clear_account, account.getUser().getScreenName()), () -> { + adapter.removeAt(i); + Account.unregister(account.getModelId()); + if (account == Application.getCurrentAccount()) { + setCurrentAccount(adapter.getItem(0)); + } + }, false); + return true; + } else { + Notificator.getInstance().publish("You can't remove last account"); + return false; + } + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + // switch current application to this account + Account account = adapter.getItem(position); + setCurrentAccount(account); + safeFinish(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_edit_list_add: { + startActivityForResult(new Intent(this, OAuthActivity.class), REQUEST_OAUTH); + break; + } + case android.R.id.home: { + safeFinish(); + } + } + return true; + } + + @Override + public void onBackPressed() { + safeFinish(); + } + + private void safeFinish() { + if (Application.getCurrentAccount() != null) { + setResult(RESULT_OK); + finish(); + } else { + Notificator.getInstance().publish("[TODO] No account selected"); // TODO + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case REQUEST_OAUTH: { + receiveOAuth(requestCode, resultCode, data); + break; + } + default: { + Logger.error(String.format("[BUG] unexpected activity result: reqCode=%d, resCode=%d", requestCode, resultCode)); + break; + } + } + } + + private void receiveOAuth(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK) { + Account account = Account.register(data.getStringExtra(OAuthSession.KEY_TOKEN), + data.getStringExtra(OAuthSession.KEY_TOKEN_SECRET), + data.getLongExtra(OAuthSession.KEY_USER_ID, -1L), + data.getStringExtra(OAuthSession.KEY_SCREEN_NAME)); + adapter.add(account); + if (Application.getCurrentAccount() == null) { + setCurrentAccount(account); + } + } else { + Logger.error(requestCode); + Notificator.getInstance().publish(R.string.notice_error_authenticate); + } + } + + private void setCurrentAccount(Account account) { + Application.setCurrentAccount(account); + InternalPreferenceHelper.getInstance().set(R.string.key_last_used_account_id, account.getModelId()); + } + + private class EditAccountsAdapter extends BaseAdapter { + private final List accounts; + + public EditAccountsAdapter() { + accounts = new ArrayList<>(Account.all()); + } + + @Override + public int getCount() { + return accounts.size(); + } + + @Override + public Account getItem(int position) { + return accounts.get(position); + } + + @Override + public long getItemId(int position) { + return accounts.get(position).getModelId(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + convertView = inflater.inflate(R.layout.menu_item_simple_text, null); + } + Account account = getItem(position); + TextView textView = (TextView) convertView.findViewById(R.id.textView_menuItem_simple); + String text = account.getUser().getScreenName(); + if (account == Application.getCurrentAccount()) { + text = "(*) " + text; + } + textView.setText(text); // TODO: show profile image + + return convertView; + } + + public int add(Account account) { + accounts.add(account); + notifyDataSetChanged(); + return accounts.size() - 1; + } + + public Account removeAt(int position) { + Account account = accounts.remove(position); + notifyDataSetChanged(); + return account; + } + } +} diff --git a/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.java b/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.java index 77658fed..6672843d 100644 --- a/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.java +++ b/app/src/main/java/net/lacolaco/smileessence/activity/OAuthActivity.java @@ -27,6 +27,7 @@ package net.lacolaco.smileessence.activity; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; @@ -41,7 +42,6 @@ import twitter4j.auth.AccessToken; public class OAuthActivity extends AppCompatActivity implements View.OnClickListener, TextWatcher { - public static final int PIN_CODE_LENGTH = 7; private TextView linkTextView; private EditText pinEditText; private Button authButton; @@ -52,6 +52,10 @@ public class OAuthActivity extends AppCompatActivity implements View.OnClickList super.onCreate(savedInstanceState); setContentView(R.layout.layout_oauth); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + linkTextView = (TextView) findViewById(R.id.textView_oauth_link); pinEditText = (EditText) findViewById(R.id.editText_oauth_pin); pinEditText.addTextChangedListener(this); @@ -96,7 +100,7 @@ public class OAuthActivity extends AppCompatActivity implements View.OnClickList @Override public void onTextChanged(CharSequence s, int start, int before, int count) { - authButton.setEnabled(s.length() == PIN_CODE_LENGTH); + authButton.setEnabled(s.length() > 0); } @Override diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/Account.java b/app/src/main/java/net/lacolaco/smileessence/entity/Account.java index a5fdd25f..0f346642 100644 --- a/app/src/main/java/net/lacolaco/smileessence/entity/Account.java +++ b/app/src/main/java/net/lacolaco/smileessence/entity/Account.java @@ -25,10 +25,10 @@ package net.lacolaco.smileessence.entity; import android.os.Handler; -import com.activeandroid.Model; import com.activeandroid.annotation.Column; import com.activeandroid.annotation.Table; import com.activeandroid.query.Delete; +import com.activeandroid.query.Select; import net.lacolaco.smileessence.twitter.task.GetUserListsTask; import net.lacolaco.smileessence.twitter.task.ShowStatusTask; import net.lacolaco.smileessence.util.BackgroundTask; @@ -39,69 +39,99 @@ import twitter4j.TwitterStream; import twitter4j.TwitterStreamFactory; import twitter4j.auth.AccessToken; -import java.util.Collections; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; -@Table(name = "Accounts") -public class Account extends Model { +public class Account { + private static Map cache; // model id -> Account private User user; + private Model model; private final Set listSubscriptions = Collections.newSetFromMap(new ConcurrentHashMap<>()); - @Column(name = "Token", notNull = true) - private String accessToken; - @Column(name = "Secret", notNull = true) - private String accessSecret; - @Column(name = "UserID", notNull = true) - private long userID; - @Column(name = "ScreenName", notNull = true) - private String screenName; + // --------------------- static methods --------------------- + public static synchronized Account get(long i) { + if (cache == null) { + throw new IllegalStateException("Load first"); + } + return cache.get(i); + } - // Required by ActiveAndroid - public Account() { - super(); + public static synchronized int count() { + return cache.size(); } - public Account(String token, String tokenSecret, long userID, String screenName) { - super(); - this.accessToken = token; - this.accessSecret = tokenSecret; - this.userID = userID; - this.screenName = screenName; + public static synchronized List all() { + return new ArrayList<>(cache.values()); } - @Deprecated - public static void deleteAll() { - new Delete().from(Account.class).execute(); + public static synchronized void load() { + cache = new LinkedHashMap<>(); + List all = new Select().from(Model.class).execute(); + for (Model model : all) { + cache.put(model.getId(), new Account(model)); + } + } + + public static synchronized Account register(String token, String tokenSecret, long userID, String screenName) { + Account account = Account.get(userID); + if (account == null) { + Model model = new Model(token, tokenSecret, userID, screenName); + model.save(); + account = new Account(model); + cache.put(model.getId(), account); + } else { + Model model = account.model; + model.accessToken = token; + model.accessSecret = tokenSecret; + model.screenName = screenName; + model.save(); + } + return account; + } + + public static synchronized Account unregister(long modelId) { + Account account = cache.remove(modelId); + if (account != null) { + Model.delete(Model.class, modelId); + } + return account; + } + + // --------------------- instance methods --------------------- + private Account(Model model) { + this.model = model; } public long getUserId() { - return userID; + return model.userID; + } + + public long getModelId() { + return model.getId(); } public Twitter getTwitter() { Twitter twitter = new TwitterFactory().getInstance(); - twitter.setOAuthAccessToken(new AccessToken(accessToken, accessSecret)); + twitter.setOAuthAccessToken(new AccessToken(model.accessToken, model.accessSecret)); return twitter; } public TwitterStream getTwitterStream() { TwitterStream stream = new TwitterStreamFactory().getInstance(); - stream.setOAuthAccessToken(new AccessToken(accessToken, accessSecret)); + stream.setOAuthAccessToken(new AccessToken(model.accessToken, model.accessSecret)); return stream; } public User getUser() { if (user == null) { - user = User.fetch(userID); + user = User.fetch(model.userID); if (user == null) { - user = User._makeSkeleton(getUserId(), screenName); + user = User._makeSkeleton(getUserId(), model.screenName); } user.addObserver(this, (user, objs) -> { - if (!this.screenName.equals(((User) user).getScreenName())) { - this.screenName = ((User) user).getScreenName(); - this.save(); + if (!model.screenName.equals(((User) user).getScreenName())) { + model.screenName = ((User) user).getScreenName(); + model.save(); } }); } @@ -153,4 +183,34 @@ public class Account extends Model { public boolean removeListSubscription(String fullName) { return listSubscriptions.remove(fullName); } -} + + @Table(name = "Accounts") + private static class Model extends com.activeandroid.Model { + @Column(name = "Token", notNull = true) + private String accessToken; + @Column(name = "Secret", notNull = true) + private String accessSecret; + @Column(name = "UserID", notNull = true) + private long userID; + @Column(name = "ScreenName", notNull = true) + private String screenName; + + // Required by ActiveAndroid + public Model() { + super(); + } + + public Model(String token, String tokenSecret, long userID, String screenName) { + super(); + this.accessToken = token; + this.accessSecret = tokenSecret; + this.userID = userID; + this.screenName = screenName; + } + + @Deprecated + public static void deleteAll() { + new Delete().from(Model.class).execute(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.java b/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.java new file mode 100644 index 00000000..ba9be9e5 --- /dev/null +++ b/app/src/main/java/net/lacolaco/smileessence/entity/RBinding.java @@ -0,0 +1,13 @@ +package net.lacolaco.smileessence.entity; + +public enum RBinding { + // Tweet + REACTION_COUNT, + FAVORITERS, + RETWEETERS, + + // User + BASIC, + DETAIL, + ; +} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/RO.java b/app/src/main/java/net/lacolaco/smileessence/entity/RO.java deleted file mode 100644 index db613730..00000000 --- a/app/src/main/java/net/lacolaco/smileessence/entity/RO.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.lacolaco.smileessence.entity; - -public enum RO { - // Tweet - REACTION_COUNT, - FAVORITERS, - RETWEETERS, - - // User - BASIC, - DETAIL, - ; -} diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.java b/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.java index 52d23617..bf7fdca9 100644 --- a/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.java +++ b/app/src/main/java/net/lacolaco/smileessence/entity/Tweet.java @@ -76,7 +76,7 @@ public class Tweet extends EntitySupport { favoriteCount = status.getFavoriteCount(); retweetCount = status.getRetweetCount(); - notifyChange(RO.REACTION_COUNT); + notifyChange(RBinding.REACTION_COUNT); } inReplyTo = status.getInReplyToStatusId(); @@ -175,13 +175,13 @@ public class Tweet extends EntitySupport { public boolean addFavoriter(long id) { boolean changed = favoriters.add(id); - if (changed) notifyChange(RO.FAVORITERS); + if (changed) notifyChange(RBinding.FAVORITERS); return changed; } public boolean removeFavoriter(long id) { boolean changed = favoriters.remove(id); - if (changed) notifyChange(RO.FAVORITERS); + if (changed) notifyChange(RBinding.FAVORITERS); return changed; } @@ -204,13 +204,13 @@ public class Tweet extends EntitySupport { public boolean addRetweet(long uid, long sid) { Long result = retweets.put(uid, sid); boolean changed = result == null || result != sid; - if (changed) notifyChange(RO.RETWEETERS); + if (changed) notifyChange(RBinding.RETWEETERS); return changed; } private boolean removeRetweet(long sid) { boolean changed = retweets.values().remove(sid); - if (changed) notifyChange(RO.RETWEETERS); + if (changed) notifyChange(RBinding.RETWEETERS); return changed; } diff --git a/app/src/main/java/net/lacolaco/smileessence/entity/User.java b/app/src/main/java/net/lacolaco/smileessence/entity/User.java index 7834e9ce..1ee7815c 100644 --- a/app/src/main/java/net/lacolaco/smileessence/entity/User.java +++ b/app/src/main/java/net/lacolaco/smileessence/entity/User.java @@ -70,7 +70,7 @@ public class User extends UIObservable { if (user.getProfileImageURLHttps() != null) profileImageUrl = user.getProfileImageURLHttps(); - notifyChange(RO.BASIC); + notifyChange(RBinding.BASIC); } if (getProfileBannerUrl() == null || !getProfileBannerUrl().equals(user.getProfileBannerURL()) || @@ -99,7 +99,7 @@ public class User extends UIObservable { if (user.getFollowersCount() != -1) followersCount = user.getFollowersCount(); - notifyChange(RO.DETAIL); + notifyChange(RBinding.DETAIL); } } diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.java b/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.java index dbf97b78..4c13e3f6 100644 --- a/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.java +++ b/app/src/main/java/net/lacolaco/smileessence/util/UIObservable.java @@ -1,6 +1,6 @@ package net.lacolaco.smileessence.util; -import net.lacolaco.smileessence.entity.RO; +import net.lacolaco.smileessence.entity.RBinding; import java.util.*; @@ -19,11 +19,11 @@ public abstract class UIObservable { } } - public void notifyChange(RO flag) { + public void notifyChange(RBinding flag) { notifyChange(EnumSet.of(flag)); } - public void notifyChange(EnumSet flags) { + public void notifyChange(EnumSet flags) { List obs = new ArrayList<>(); synchronized(this) { obs.addAll(observers.values()); diff --git a/app/src/main/java/net/lacolaco/smileessence/util/UIObserver.java b/app/src/main/java/net/lacolaco/smileessence/util/UIObserver.java index adfece0a..63918607 100644 --- a/app/src/main/java/net/lacolaco/smileessence/util/UIObserver.java +++ b/app/src/main/java/net/lacolaco/smileessence/util/UIObserver.java @@ -1,9 +1,9 @@ package net.lacolaco.smileessence.util; -import net.lacolaco.smileessence.entity.RO; +import net.lacolaco.smileessence.entity.RBinding; import java.util.EnumSet; public interface UIObserver { - void update(UIObservable observable, EnumSet flags); + void update(UIObservable observable, EnumSet flags); } diff --git a/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java index e98a56db..cabe46ce 100644 --- a/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java +++ b/app/src/main/java/net/lacolaco/smileessence/view/SettingFragment.java @@ -33,10 +33,9 @@ import android.preference.Preference; import android.preference.PreferenceFragment; import android.text.TextUtils; import net.lacolaco.smileessence.R; +import net.lacolaco.smileessence.activity.ManageAccountsActivity; import net.lacolaco.smileessence.activity.LicenseActivity; -import net.lacolaco.smileessence.entity.Account; import net.lacolaco.smileessence.notification.Notificator; -import net.lacolaco.smileessence.view.dialog.ConfirmDialogFragment; import net.lacolaco.smileessence.view.dialog.SimpleDialogFragment; import static android.content.SharedPreferences.OnSharedPreferenceChangeListener; @@ -94,12 +93,8 @@ public class SettingFragment extends PreferenceFragment implements OnSharedPrefe R.layout.dialog_app_info, getString(R.string.dialog_title_about)); DialogHelper.showDialog(getActivity(), informationDialog); - } else if (key.contentEquals(getString(R.string.key_setting_clear_account))) { - ConfirmDialogFragment.show(getActivity(), getString(R.string.dialog_confirm_clear_account), () -> { - Notificator.getInstance().publish(R.string.notice_cleared_account); - Account.deleteAll(); - getActivity().finish(); - }, false); + } else if (key.contentEquals(getString(R.string.key_setting_accounts))) { + openManageAccountsActivity(); } else if (key.contentEquals(getString(R.string.key_setting_licenses))) { openLicenseActivity(); } @@ -119,6 +114,8 @@ public class SettingFragment extends PreferenceFragment implements OnSharedPrefe public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.setting); + Preference manageAccounts = findPreference(R.string.key_setting_accounts); + manageAccounts.setOnPreferenceClickListener(this); EditTextPreference textSizePreference = (EditTextPreference) findPreference(R.string.key_setting_text_size); textSizePreference.setSummary(textSizePreference.getText()); textSizePreference.setOnPreferenceChangeListener(this); @@ -132,8 +129,6 @@ public class SettingFragment extends PreferenceFragment implements OnSharedPrefe timelinesPreference.setOnPreferenceChangeListener(this); Preference appInfoPreference = findPreference(R.string.key_setting_application_information); appInfoPreference.setOnPreferenceClickListener(this); - Preference clearAccount = findPreference(R.string.key_setting_clear_account); - clearAccount.setOnPreferenceClickListener(this); Preference license = findPreference(R.string.key_setting_licenses); license.setOnPreferenceClickListener(this); } @@ -163,6 +158,11 @@ public class SettingFragment extends PreferenceFragment implements OnSharedPrefe getActivity().startActivity(intent); } + private void openManageAccountsActivity() { + Intent intent = new Intent(getActivity(), ManageAccountsActivity.class); + getActivity().startActivity(intent); + } + private void setSummaryCurrentValue() { EditTextPreference textSizePreference = (EditTextPreference) findPreference(R.string.key_setting_text_size); textSizePreference.setSummary(textSizePreference.getText()); diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java index 6ec85e92..206c795a 100644 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/StatusDetailDialogFragment.java @@ -37,7 +37,7 @@ import net.lacolaco.smileessence.command.Command; import net.lacolaco.smileessence.command.CommandOpenURL; import net.lacolaco.smileessence.data.PostState; import net.lacolaco.smileessence.entity.Account; -import net.lacolaco.smileessence.entity.RO; +import net.lacolaco.smileessence.entity.RBinding; import net.lacolaco.smileessence.entity.Tweet; import net.lacolaco.smileessence.notification.NotificationType; import net.lacolaco.smileessence.notification.Notificator; @@ -157,9 +157,9 @@ public class StatusDetailDialogFragment extends StackableDialogFragment implemen bundle.attach(tweet, (x, changes) -> { if (getActivity() != null) { - if (changes.contains(RO.REACTION_COUNT)) + if (changes.contains(RBinding.REACTION_COUNT)) updateViewReactions(view, tweet); - if (changes.contains(RO.FAVORITERS) || changes.contains(RO.RETWEETERS)) + if (changes.contains(RBinding.FAVORITERS) || changes.contains(RBinding.RETWEETERS)) updateViewButtons(view, tweet); } }); diff --git a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java index e11b117c..8bfc119d 100644 --- a/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java +++ b/app/src/main/java/net/lacolaco/smileessence/view/dialog/UserDetailDialogFragment.java @@ -43,7 +43,7 @@ import net.lacolaco.smileessence.command.Command; import net.lacolaco.smileessence.command.CommandOpenURL; import net.lacolaco.smileessence.data.ImageCache; import net.lacolaco.smileessence.entity.Account; -import net.lacolaco.smileessence.entity.RO; +import net.lacolaco.smileessence.entity.RBinding; import net.lacolaco.smileessence.entity.Tweet; import net.lacolaco.smileessence.entity.User; import net.lacolaco.smileessence.notification.NotificationType; @@ -308,9 +308,9 @@ public class UserDetailDialogFragment extends StackableDialogFragment implements observerBundle.attach(user, (x, changes) -> { if (getActivity() != null) { - if (changes.contains(RO.BASIC)) + if (changes.contains(RBinding.BASIC)) updateUserDataBasic(user); - if (changes.contains(RO.DETAIL)) + if (changes.contains(RBinding.DETAIL)) updateUserDataDetail(user); } }); diff --git a/app/src/main/java/net/lacolaco/smileessence/viewmodel/EventViewModel.java b/app/src/main/java/net/lacolaco/smileessence/viewmodel/EventViewModel.java index 4c3ba160..f586f2e2 100644 --- a/app/src/main/java/net/lacolaco/smileessence/viewmodel/EventViewModel.java +++ b/app/src/main/java/net/lacolaco/smileessence/viewmodel/EventViewModel.java @@ -33,7 +33,7 @@ import com.android.volley.toolbox.NetworkImageView; import net.lacolaco.smileessence.Application; import net.lacolaco.smileessence.R; import net.lacolaco.smileessence.data.ImageCache; -import net.lacolaco.smileessence.entity.RO; +import net.lacolaco.smileessence.entity.RBinding; import net.lacolaco.smileessence.entity.Tweet; import net.lacolaco.smileessence.entity.User; import net.lacolaco.smileessence.preference.UserPreferenceHelper; @@ -147,7 +147,7 @@ public class EventViewModel implements IViewModel { final View finalView = convertedView; bundle.attach(source, (x, changes) -> { - if (changes.contains(RO.BASIC)) + if (changes.contains(RBinding.BASIC)) updateViewUser(finalView); }); diff --git a/app/src/main/java/net/lacolaco/smileessence/viewmodel/MessageViewModel.java b/app/src/main/java/net/lacolaco/smileessence/viewmodel/MessageViewModel.java index 07d2b42c..ecb47823 100644 --- a/app/src/main/java/net/lacolaco/smileessence/viewmodel/MessageViewModel.java +++ b/app/src/main/java/net/lacolaco/smileessence/viewmodel/MessageViewModel.java @@ -35,7 +35,7 @@ import net.lacolaco.smileessence.R; import net.lacolaco.smileessence.data.ImageCache; import net.lacolaco.smileessence.entity.Account; import net.lacolaco.smileessence.entity.DirectMessage; -import net.lacolaco.smileessence.entity.RO; +import net.lacolaco.smileessence.entity.RBinding; import net.lacolaco.smileessence.preference.UserPreferenceHelper; import net.lacolaco.smileessence.util.NameStyles; import net.lacolaco.smileessence.util.StringUtils; @@ -110,7 +110,7 @@ public class MessageViewModel implements IViewModel { final View finalView = convertedView; bundle.attach(directMessage.getSender(), (x, changes) -> { - if (changes.contains(RO.BASIC)) + if (changes.contains(RBinding.BASIC)) updateViewSender(activity, finalView); }); diff --git a/app/src/main/java/net/lacolaco/smileessence/viewmodel/StatusViewModel.java b/app/src/main/java/net/lacolaco/smileessence/viewmodel/StatusViewModel.java index 9b61319f..cb7cde63 100644 --- a/app/src/main/java/net/lacolaco/smileessence/viewmodel/StatusViewModel.java +++ b/app/src/main/java/net/lacolaco/smileessence/viewmodel/StatusViewModel.java @@ -36,7 +36,7 @@ import net.lacolaco.smileessence.Application; import net.lacolaco.smileessence.R; import net.lacolaco.smileessence.activity.MainActivity; import net.lacolaco.smileessence.data.ImageCache; -import net.lacolaco.smileessence.entity.RO; +import net.lacolaco.smileessence.entity.RBinding; import net.lacolaco.smileessence.entity.Tweet; import net.lacolaco.smileessence.preference.UserPreferenceHelper; import net.lacolaco.smileessence.util.*; @@ -113,11 +113,11 @@ public class StatusViewModel implements IViewModel { final View view = convertedView; bundle.attach(tweet, (x, changes) -> { - if (changes.contains(RO.FAVORITERS)) + if (changes.contains(RBinding.FAVORITERS)) updateViewFavorited(((MainActivity) activity), view); }); bundle.attach(tweet.getUser(), (x, changes) -> { - if (changes.contains(RO.BASIC)) + if (changes.contains(RBinding.BASIC)) updateViewUser(((MainActivity) activity), view); }); diff --git a/app/src/main/res/layout/layout_edit_list.xml b/app/src/main/res/layout/layout_edit_list.xml index 3311477f..396fb732 100644 --- a/app/src/main/res/layout/layout_edit_list.xml +++ b/app/src/main/res/layout/layout_edit_list.xml @@ -26,6 +26,7 @@ @@ -34,7 +35,8 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> + android:background="?attr/colorPrimary" + app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> @@ -33,7 +34,8 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" - android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> + android:background="?attr/colorPrimary" + app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> + android:orientation="vertical"> + android:background="?attr/colorPrimary" + app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> + + + diff --git a/app/src/main/res/layout/layout_oauth.xml b/app/src/main/res/layout/layout_oauth.xml index 077fcaf9..61af223d 100644 --- a/app/src/main/res/layout/layout_oauth.xml +++ b/app/src/main/res/layout/layout_oauth.xml @@ -23,43 +23,59 @@ ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ~ SOFTWARE. --> + - + - + - + - + + + + +