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
+}