diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index dd1e3d8d..19ecbea0 100755 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -68,6 +68,9 @@ Initializing… Reseting… Loading app list… + Yes + No + Remove this profile? Reset diff --git a/src/main/res/xml/pref_proxy.xml b/src/main/res/xml/pref_proxy.xml index 5c9b61cf..4b89448f 100755 --- a/src/main/res/xml/pref_proxy.xml +++ b/src/main/res/xml/pref_proxy.xml @@ -1,12 +1,12 @@ - - + updateSummaryEditTextPreference(pref, profile.name) + case Key.profileName => updateProfileEditTextPreference(pref, profile.name) case Key.proxy => updateSummaryEditTextPreference(pref, profile.host) case Key.remotePort => updateSummaryEditTextPreference(pref, profile.remotePort.toString) case Key.localPort => updateSummaryEditTextPreference(pref, profile.localPort.toString) @@ -283,7 +288,6 @@ object Shadowsocks { class Shadowsocks extends UnifiedSherlockPreferenceActivity with CompoundButton.OnCheckedChangeListener - with OnSharedPreferenceChangeListener with MenuAdapter.MenuListener{ private val MSG_CRASH_RECOVER: Int = 1 @@ -300,7 +304,8 @@ class Shadowsocks lazy val settings = PreferenceManager.getDefaultSharedPreferences(this) lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE) - lazy val receiver = new StateBroadcastReceiver + lazy val stateReceiver = new StateBroadcastReceiver + lazy val preferenceReceiver = new PreferenceBroadcastReceiver lazy val drawer = MenuDrawer.attach(this) lazy val menuAdapter = new MenuAdapter(this, getMenuList) lazy val listView = new ListView(this) @@ -319,6 +324,16 @@ class Shadowsocks } } + private def showProgress(msg: String): Handler = { + clearDialog() + progressDialog = ProgressDialog.show(this, "", msg, true, false) + new Handler { + override def handleMessage(msg: Message) { + clearDialog() + } + } + } + private def copyAssets(path: String) { val assetManager: AssetManager = getAssets var files: Array[String] = null @@ -366,13 +381,6 @@ class Shadowsocks } } - override def onSharedPreferenceChanged(prefs: SharedPreferences, key: String) { - if (key == Key.profileName) { - profileManager.save() - menuAdapter.updateList(getMenuList, Shadowsocks.currentProfile.id) - } - } - private def crash_recovery() { val sb = new StringBuilder @@ -415,9 +423,7 @@ class Shadowsocks } def prepareStartService() { - clearDialog() - progressDialog = ProgressDialog - .show(Shadowsocks.this, "", getString(R.string.connecting), true, true) + showProgress(getString(R.string.connecting)) spawn { if (isVpnEnabled) { val intent = VpnService.prepare(this) @@ -509,7 +515,9 @@ class Shadowsocks title.setText(R.string.app_name) switchButton = switchLayout.findViewById(R.id.switchButton).asInstanceOf[Switch] - registerReceiver(receiver, new IntentFilter(Action.UPDATE_STATE)) + + registerReceiver(stateReceiver, new IntentFilter(Action.UPDATE_STATE)) + registerReceiver(preferenceReceiver, new IntentFilter(Action.UPDATE_PREFS)) val init: Boolean = !Shadowsocks.isServiceStarted(this) if (init) { @@ -554,12 +562,15 @@ class Shadowsocks def addProfile(id: Int) { drawer.closeMenu(true) + val h = showProgress(getString(R.string.loading)) + handler.postDelayed(new Runnable { def run() { Shadowsocks.currentProfile = profileManager.reload(id) updatePreferenceScreen() profileManager.save() menuAdapter.updateList(getMenuList, Shadowsocks.currentProfile.id) + h.sendEmptyMessage(0) } }, 600) @@ -569,12 +580,15 @@ class Shadowsocks def updateProfile(id: Int) { drawer.closeMenu(true) + val h = showProgress(getString(R.string.loading)) + handler.postDelayed(new Runnable { def run() { Shadowsocks.currentProfile = profileManager.reload(id) updatePreferenceScreen() menuAdapter.setActiveId(id) menuAdapter.notifyDataSetChanged() + h.sendEmptyMessage(0) } }, 600) @@ -584,18 +598,25 @@ class Shadowsocks def delProfile(id: Int): Boolean = { drawer.closeMenu(true) - handler.postDelayed(new Runnable { - def run() { - profileManager.delProfile(id) - val profileId = { - val profiles = profileManager.getAllProfiles.getOrElse(List[Profile]()) - if (profiles.isEmpty) -1 else profiles(0).id + new AlertDialog.Builder(this) + .setMessage(R.string.remove_profile) + .setCancelable(false) + .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + override def onClick(dialog: DialogInterface, i: Int) = dialog.cancel() + }) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + override def onClick(dialog: DialogInterface, i: Int) { + profileManager.delProfile(id) + val profileId = { + val profiles = profileManager.getAllProfiles.getOrElse(List[Profile]()) + if (profiles.isEmpty) -1 else profiles(0).id + } + Shadowsocks.currentProfile = profileManager.load(profileId) + updatePreferenceScreen() + menuAdapter.updateList(getMenuList, Shadowsocks.currentProfile.id) + dialog.dismiss() } - Shadowsocks.currentProfile = profileManager.load(profileId) - updatePreferenceScreen() - menuAdapter.updateList(getMenuList, Shadowsocks.currentProfile.id) - } - }, 600) + }).create().show() if (!isSinglePane) sendBroadcast(new Intent(Action.UPDATE_FRAGMENT)) @@ -652,7 +673,6 @@ class Shadowsocks protected override def onPause() { super.onPause() prepared = false - settings.unregisterOnSharedPreferenceChangeListener(this) } protected override def onResume() { @@ -687,7 +707,6 @@ class Shadowsocks switchButton.setOnCheckedChangeListener(this) - settings.registerOnSharedPreferenceChangeListener(this) } private def setPreferenceEnabled(enabled: Boolean) { @@ -737,7 +756,8 @@ class Shadowsocks override def onDestroy() { super.onDestroy() Crouton.cancelAllCroutons() - unregisterReceiver(receiver) + unregisterReceiver(stateReceiver) + unregisterReceiver(preferenceReceiver) new BackupManager(this).dataChanged() } @@ -752,13 +772,8 @@ class Shadowsocks } private def recovery() { - clearDialog() - progressDialog = ProgressDialog.show(this, "", getString(R.string.recovering), true, true) - val h: Handler = new Handler { - override def handleMessage(msg: Message) { - clearDialog() - } - } + val h = showProgress(getString(R.string.recovering)) + serviceStop() spawn { reset() @@ -767,13 +782,7 @@ class Shadowsocks } private def flushDnsCache() { - clearDialog() - progressDialog = ProgressDialog.show(this, "", getString(R.string.flushing), true, true) - val h: Handler = new Handler { - override def handleMessage(msg: Message) { - clearDialog() - } - } + val h = showProgress(getString(R.string.flushing)) spawn { Utils.toggleAirplaneMode(getBaseContext) h.sendEmptyMessage(0) @@ -945,6 +954,13 @@ class Shadowsocks } } + class PreferenceBroadcastReceiver extends BroadcastReceiver { + override def onReceive(context: Context, intent: Intent) { + Shadowsocks.currentProfile = profileManager.save() + menuAdapter.updateList(getMenuList, Shadowsocks.currentProfile.id) + } + } + class StateBroadcastReceiver extends BroadcastReceiver { override def onReceive(context: Context, intent: Intent) { val state = intent.getIntExtra(Extra.STATE, State.INIT) diff --git a/src/main/scala/com/github/shadowsocks/Utils.scala b/src/main/scala/com/github/shadowsocks/Utils.scala index e3e63e9c..cb113a73 100644 --- a/src/main/scala/com/github/shadowsocks/Utils.scala +++ b/src/main/scala/com/github/shadowsocks/Utils.scala @@ -157,6 +157,7 @@ object Action { val CLOSE = "com.github.shadowsocks.ACTION_SHUTDOWN" val UPDATE_STATE = "com.github.shadowsocks.ACTION_UPDATE_STATE" val UPDATE_FRAGMENT = "com.github.shadowsocks.ACTION_UPDATE_FRAGMENT" + val UPDATE_PREFS = "com.github.shadowsocks.ACTION_UPDATE_PREFS" } object Extra { diff --git a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala index d4772cdb..6bfce5af 100644 --- a/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala +++ b/src/main/scala/com/github/shadowsocks/database/ProfileManager.scala @@ -56,6 +56,17 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { } } + def updateProfile(profile: Profile): Boolean = { + try { + dbHelper.profileDao.update(profile) + true + } catch { + case ex: Exception => + Log.e(Shadowsocks.TAG, "addProfile", ex) + false + } + } + def getProfile(id: Int): Option[Profile] = { try { dbHelper.profileDao.queryForId(id) match { @@ -122,9 +133,11 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { profile } - def save() { + def save(): Profile = { val profile = new Profile() + profile.id = settings.getInt(Key.profileId, -1) + profile.global = settings.getBoolean(Key.isGlobalProxy, false) profile.chnroute = settings.getBoolean(Key.isGFWList, false) profile.bypass = settings.getBoolean(Key.isBypassApps, false) @@ -149,10 +162,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { } profile.individual = settings.getString(Key.proxied, "") - profile.id = settings.getInt(Key.profileId, -1) + updateProfile(profile) - Log.d(Shadowsocks.TAG, "save " + profile.id + " " + profile.name) - - createOrUpdateProfile(profile) + profile } } diff --git a/src/main/scala/com/github/shadowsocks/preferences/ProfileEditTextPreference.scala b/src/main/scala/com/github/shadowsocks/preferences/ProfileEditTextPreference.scala new file mode 100644 index 00000000..9028c600 --- /dev/null +++ b/src/main/scala/com/github/shadowsocks/preferences/ProfileEditTextPreference.scala @@ -0,0 +1,73 @@ +/* + * Shadowsocks - A shadowsocks client for Android + * Copyright (C) 2013 + * + * This program 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. + * + * This program 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 this program. If not, see . + * + * + * ___====-_ _-====___ + * _--^^^#####// \\#####^^^--_ + * _-^##########// ( ) \\##########^-_ + * -############// |\^^/| \\############- + * _/############// (@::@) \\############\_ + * /#############(( \\// ))#############\ + * -###############\\ (oo) //###############- + * -#################\\ / VV \ //#################- + * -###################\\/ \//###################- + * _#/|##########/\######( /\ )######/\##########|\#_ + * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| + * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' + * ` ` ` ` / | | | | \ ' ' ' ' + * ( | | | | ) + * __\ | | | | /__ + * (vvv(VVV)(VVV)vvv) + * + * HERE BE DRAGONS + * + */ + +package com.github.shadowsocks.preferences + +import android.content.{Intent, Context} +import android.preference.EditTextPreference +import android.util.AttributeSet +import com.github.shadowsocks.Action + +class ProfileEditTextPreference(context: Context, attrs: AttributeSet, defStyle: Int) + extends EditTextPreference(context, attrs, defStyle) { + + def this(context: Context, attrs: AttributeSet) = { + this(context, attrs, android.R.attr.editTextPreferenceStyle) + mDefaultSummary = getSummary + } + + override def setSummary(summary: CharSequence) { + if (summary.toString.isEmpty) { + super.setSummary(mDefaultSummary) + } else { + super.setSummary(summary) + } + context.sendBroadcast(new Intent(Action.UPDATE_PREFS)) + } + + def resetSummary(summary: CharSequence) { + if (summary.toString.isEmpty) { + super.setSummary(mDefaultSummary) + } else { + super.setSummary(summary) + } + } + + private var mDefaultSummary: CharSequence = getSummary +}