diff --git a/src/main/res/drawable-anydpi-v21/ic_check.xml b/src/main/res/drawable-anydpi-v21/ic_check.xml
deleted file mode 100644
index 6541ee3e..00000000
--- a/src/main/res/drawable-anydpi-v21/ic_check.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/src/main/res/drawable-hdpi/ic_check.png b/src/main/res/drawable-hdpi/ic_check.png
deleted file mode 100644
index 729f2901..00000000
Binary files a/src/main/res/drawable-hdpi/ic_check.png and /dev/null differ
diff --git a/src/main/res/drawable-mdpi/ic_check.png b/src/main/res/drawable-mdpi/ic_check.png
deleted file mode 100644
index dfcb55d0..00000000
Binary files a/src/main/res/drawable-mdpi/ic_check.png and /dev/null differ
diff --git a/src/main/res/drawable-xhdpi/ic_check.png b/src/main/res/drawable-xhdpi/ic_check.png
deleted file mode 100644
index 3b2b65d2..00000000
Binary files a/src/main/res/drawable-xhdpi/ic_check.png and /dev/null differ
diff --git a/src/main/res/drawable-xxhdpi/ic_check.png b/src/main/res/drawable-xxhdpi/ic_check.png
deleted file mode 100644
index 2c2ad771..00000000
Binary files a/src/main/res/drawable-xxhdpi/ic_check.png and /dev/null differ
diff --git a/src/main/res/drawable-xxxhdpi/ic_check.png b/src/main/res/drawable-xxxhdpi/ic_check.png
deleted file mode 100644
index d670618c..00000000
Binary files a/src/main/res/drawable-xxxhdpi/ic_check.png and /dev/null differ
diff --git a/src/main/res/layout/layout_tasker.xml b/src/main/res/layout/layout_tasker.xml
index 516fc5d4..c33cedeb 100644
--- a/src/main/res/layout/layout_tasker.xml
+++ b/src/main/res/layout/layout_tasker.xml
@@ -1,12 +1,21 @@
-
+
-
+
+
+
+
diff --git a/src/main/res/layout/layout_tasker_toggle_service.xml b/src/main/res/layout/layout_tasker_toggle_service.xml
deleted file mode 100644
index e182bc14..00000000
--- a/src/main/res/layout/layout_tasker_toggle_service.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
diff --git a/src/main/res/menu/tasker_menu.xml b/src/main/res/menu/tasker_menu.xml
deleted file mode 100644
index 670f5ce0..00000000
--- a/src/main/res/menu/tasker_menu.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
\ No newline at end of file
diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml
index 8e7e5697..723562c1 100755
--- a/src/main/res/values-zh/strings.xml
+++ b/src/main/res/values-zh/strings.xml
@@ -97,7 +97,10 @@
已删除
撤销
- 切换服务状态
- 保存
+ 启动服务
+ 连接到当前服务器
+ 连接到 %s
+ 切换到 %s
+ 使用当前配置
diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml
index f5b7f3ac..3f3fa9ef 100644
--- a/src/main/res/values/arrays.xml
+++ b/src/main/res/values/arrays.xml
@@ -226,14 +226,4 @@
- 204.0.0.0/6
- 208.0.0.0/4
-
-
- - Toggle service
- - Switch profile
-
-
-
- - toggle_service
- - switch_profile
-
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 7596b654..2893b509 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -103,12 +103,9 @@
Undo
- Toggle service state
- Save
- Turn service %s
- No action was selected
- No profile was selected
- Switch profile to %s
- on
- off
+ Start the service
+ Connect to the current server
+ Connect to %s
+ Switch to %s
+ Use the current profile
diff --git a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala
index 77aa09ce..e5c3df49 100644
--- a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala
+++ b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala
@@ -93,7 +93,7 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
private class ProfilesAdapter extends RecyclerView.Adapter[ProfileViewHolder] {
private val recycleBin = new ArrayBuffer[(Int, Profile)]
private var profiles = new ArrayBuffer[Profile]
- profiles ++= ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List[Profile]())
+ profiles ++= ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List.empty[Profile])
def getItemCount = profiles.length
diff --git a/src/main/scala/com/github/shadowsocks/TaskerActivity.scala b/src/main/scala/com/github/shadowsocks/TaskerActivity.scala
index 3919659d..8f0c40f5 100644
--- a/src/main/scala/com/github/shadowsocks/TaskerActivity.scala
+++ b/src/main/scala/com/github/shadowsocks/TaskerActivity.scala
@@ -39,25 +39,63 @@
package com.github.shadowsocks
import android.app.Activity
-import android.content.Intent
-import android.os.Bundle
-import android.support.v4.app.{Fragment, ListFragment}
+import android.content.res.Resources
+import android.os.{Build, Bundle}
import android.support.v7.app.AppCompatActivity
-import android.support.v7.widget.Toolbar
-import android.util.Log
+import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar}
import android.view.{LayoutInflater, View, ViewGroup}
-import android.widget.AdapterView.OnItemClickListener
-import android.widget._
+import android.widget.{Switch, CheckedTextView}
import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.helper.TaskerSettings
-import com.twofortyfouram.locale.api.{Intent => ApiIntent}
/**
* @author CzBiX
*/
class TaskerActivity extends AppCompatActivity {
- var taskerOption: TaskerSettings = _
- var actionSelected: Boolean = false
+ private class ProfileViewHolder(val view: View) extends RecyclerView.ViewHolder(view) with View.OnClickListener {
+ {
+ val typedArray = obtainStyledAttributes(Array(android.R.attr.selectableItemBackground))
+ view.setBackgroundResource(typedArray.getResourceId(0, 0))
+ typedArray.recycle
+ }
+ private var item: Profile = _
+ private val text = itemView.findViewById(android.R.id.text1).asInstanceOf[CheckedTextView]
+ itemView.setOnClickListener(this)
+
+ def bindDefault {
+ item = null
+ text.setText(R.string.profile_default)
+ text.setChecked(taskerOption.profileId < 0)
+ }
+ def bind(item: Profile) {
+ this.item = item
+ text.setText(item.name)
+ text.setChecked(taskerOption.profileId == item.id)
+ }
+
+ def onClick(v: View) {
+ taskerOption.switchOn = switch.isChecked
+ taskerOption.profileId = if (item == null) -1 else item.id
+ setResult(Activity.RESULT_OK, taskerOption.toIntent(TaskerActivity.this))
+ finish
+ }
+ }
+
+ private class ProfilesAdapter extends RecyclerView.Adapter[ProfileViewHolder] {
+ private val profiles = ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List.empty[Profile])
+ def getItemCount = 1 + profiles.length
+ def onBindViewHolder(vh: ProfileViewHolder, i: Int) = i match {
+ case 0 => vh.bindDefault
+ case _ => vh.bind(profiles(i - 1))
+ }
+ private val name = "select_dialog_singlechoice_" + (if (Build.VERSION.SDK_INT >= 21) "material" else "holo")
+ def onCreateViewHolder(vg: ViewGroup, i: Int) = new ProfileViewHolder(LayoutInflater.from(vg.getContext)
+ .inflate(Resources.getSystem.getIdentifier(name, "layout", "android"), vg, false))
+ }
+
+ private var taskerOption: TaskerSettings = _
+ private var switch: Switch = _
+ private val profilesAdapter = new ProfilesAdapter
override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState)
@@ -67,155 +105,14 @@ class TaskerActivity extends AppCompatActivity {
toolbar.setTitle(R.string.app_name)
toolbar.setNavigationIcon(R.drawable.ic_close)
toolbar.setNavigationOnClickListener(_ => finish())
- toolbar.inflateMenu(R.menu.tasker_menu)
- toolbar.setOnMenuItemClickListener(_.getItemId match {
- case R.id.save =>
- saveResult()
- true
- case _ => false
- })
- loadSettings()
- loadFragment()
- }
-
- private def loadSettings() {
- val intent: Intent = getIntent
- if (intent.getAction != ApiIntent.ACTION_EDIT_SETTING) {
- Log.w(Shadowsocks.TAG, "unknown tasker action")
- finish()
- return
- }
-
- taskerOption = TaskerSettings.fromIntent(intent)
- }
-
- private def loadFragment() {
- actionSelected = !taskerOption.isEmpty
- val fragment: Fragment = taskerOption.action match {
- case TaskerSettings.ACTION_TOGGLE_SERVICE =>
- new ToggleServiceFragment
- case TaskerSettings.ACTION_SWITCH_PROFILE =>
- new ProfileChoiceFragment
- case _ =>
- val fragment: ActionChoiceFragment = new ActionChoiceFragment
- fragment.onItemClickedListener = (_, _, _, id) => {
- taskerOption.action = getResources.getStringArray(R.array.tasker_action_value)(id.toInt)
- loadFragment()
- actionSelected = true
- }
- fragment
- }
-
- getSupportFragmentManager.beginTransaction()
- .replace(R.id.fragment, fragment)
- .commit()
- }
-
- private def saveResult() {
- if (actionSelected) {
- val fragment: OptionFragment = getSupportFragmentManager.findFragmentById(R.id.fragment).asInstanceOf[OptionFragment]
- if (fragment.saveResult()) {
- setResult(Activity.RESULT_OK, taskerOption.toIntent(this))
- finish()
- }
- } else {
- Toast.makeText(this, R.string.no_action_selected, Toast.LENGTH_SHORT).show()
- }
- }
-
- private class ActionChoiceFragment extends ListFragment {
- var onItemClickedListener: OnItemClickListener = _
-
- override def onActivityCreated(savedInstanceState: Bundle) {
- super.onActivityCreated(savedInstanceState)
-
- val adapter = ArrayAdapter.createFromResource(getActivity, R.array.tasker_action_name, android.R.layout.simple_selectable_list_item)
-
- setListAdapter(adapter)
- }
-
- override def onListItemClick(l: ListView, v: View, position: Int, id: Long) {
- if (onItemClickedListener != null) {
- onItemClickedListener.onItemClick(l, v, position, id)
- }
- }
- }
-
- private class ToggleServiceFragment extends Fragment with OptionFragment {
- var switch: Switch = _
-
- override def onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle): View = {
- val view: View = inflater.inflate(R.layout.layout_tasker_toggle_service, container, false)
-
- switch = view.findViewById(R.id.service_switch).asInstanceOf[Switch]
- view
- }
-
- override def onActivityCreated(savedInstanceState: Bundle) {
- super.onActivityCreated(savedInstanceState)
-
- if (!taskerOption.isEmpty) {
- switch.setChecked(taskerOption.isStart)
- }
- }
-
- override def saveResult() = {
- taskerOption.action = TaskerSettings.ACTION_TOGGLE_SERVICE
- taskerOption.isStart = switch.isChecked
- true
- }
- }
-
- private class ProfileChoiceFragment extends ListFragment with OptionFragment {
- override def onActivityCreated(savedInstanceState: Bundle) {
- super.onActivityCreated(savedInstanceState)
-
- import scala.collection.JavaConverters._
- val profiles = ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List.empty)
- val adapter = new ArrayAdapter[Profile](getActivity, 0, android.R.id.text1, profiles.asJava) {
- override def getView(position: Int, convertView: View, parent: ViewGroup): View = {
- val view: TextView = if (convertView == null) {
- val inflater = LayoutInflater.from(parent.getContext)
- inflater.inflate(android.R.layout.simple_list_item_single_choice, parent, false).asInstanceOf[TextView]
- } else {
- convertView.asInstanceOf[TextView]
- }
-
- view.setText(getItem(position).name)
- view
- }
- }
-
- setListAdapter(adapter)
-
- val listView: ListView = getListView
- listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE)
-
- if (!taskerOption.isEmpty) {
- val index = profiles.indexWhere(_.id == taskerOption.profileId)
- if (index > -1) {
- listView.setItemChecked(index, true)
- }
- }
- }
-
- override def saveResult() = {
- taskerOption.action = TaskerSettings.ACTION_SWITCH_PROFILE
- val listView = getListView
- val item = listView.getItemAtPosition(listView.getCheckedItemPosition)
- if (item == null) {
- Toast.makeText(getActivity, R.string.no_profile_selected, Toast.LENGTH_SHORT).show()
- false
- } else {
- taskerOption.profileId = item.asInstanceOf[Profile].id
- true
- }
- }
- }
-
- trait OptionFragment extends Fragment {
- def saveResult(): Boolean
+ taskerOption = TaskerSettings.fromIntent(getIntent)
+ switch = findViewById(R.id.serviceSwitch).asInstanceOf[Switch]
+ switch.setChecked(taskerOption.switchOn)
+ val profilesList = findViewById(R.id.profilesList).asInstanceOf[RecyclerView]
+ profilesList.setLayoutManager(new LinearLayoutManager(this))
+ profilesList.setItemAnimator(new DefaultItemAnimator)
+ profilesList.setAdapter(profilesAdapter)
}
}
diff --git a/src/main/scala/com/github/shadowsocks/TaskerReceiver.scala b/src/main/scala/com/github/shadowsocks/TaskerReceiver.scala
index 06862287..a99c0284 100644
--- a/src/main/scala/com/github/shadowsocks/TaskerReceiver.scala
+++ b/src/main/scala/com/github/shadowsocks/TaskerReceiver.scala
@@ -39,7 +39,6 @@
package com.github.shadowsocks
import android.content.{BroadcastReceiver, Context, Intent}
-import android.util.Log
import com.github.shadowsocks.helper.TaskerSettings
import com.github.shadowsocks.utils.Utils
@@ -47,20 +46,15 @@ import com.github.shadowsocks.utils.Utils
* @author CzBiX
*/
class TaskerReceiver extends BroadcastReceiver {
- override def onReceive(context: Context, intent: Intent): Unit = {
- val settings: TaskerSettings = TaskerSettings.fromIntent(intent)
-
- settings.action match {
- case TaskerSettings.ACTION_TOGGLE_SERVICE =>
- if (settings.isStart) {
- Utils.startSsService(context)
- } else {
- Utils.stopSsService(context)
- }
- case TaskerSettings.ACTION_SWITCH_PROFILE =>
+ override def onReceive(context: Context, intent: Intent) {
+ val settings = TaskerSettings.fromIntent(intent)
+ val switched = ShadowsocksApplication.profileManager.getProfile(settings.profileId) match {
+ case Some(p) =>
+ Utils.stopSsService(context)
ShadowsocksApplication.switchProfile(settings.profileId)
- case _ =>
- Log.e(Shadowsocks.TAG, s"unknown tasker action: ${settings.action}")
+ true
+ case _ => false
}
+ if (settings.switchOn) Utils.startSsService(context) else if (!switched) Utils.stopSsService(context)
}
}
diff --git a/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala b/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala
index a9cbc1bd..8fadf78a 100644
--- a/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala
+++ b/src/main/scala/com/github/shadowsocks/helper/TaskerSettings.scala
@@ -40,78 +40,35 @@ package com.github.shadowsocks.helper
import android.content.{Context, Intent}
import android.os.Bundle
-import android.util.Log
-import com.github.shadowsocks.{R, Shadowsocks, ShadowsocksApplication}
+import com.github.shadowsocks.{R, ShadowsocksApplication}
import com.twofortyfouram.locale.api.{Intent => ApiIntent}
object TaskerSettings {
- val ACTION_UNKNOWN = "unknown"
- val ACTION_TOGGLE_SERVICE = "toggle_service"
- val ACTION_SWITCH_PROFILE = "switch_profile"
+ private val KEY_ACTION = "action"
+ private val KEY_SWITCH_ON = "switch_on"
+ private val KEY_PROFILE_ID = "profile_id"
- def fromIntent(intent: Intent): TaskerSettings = {
- val bundle: Bundle = if (intent.hasExtra(ApiIntent.EXTRA_BUNDLE))
- intent.getBundleExtra(ApiIntent.EXTRA_BUNDLE) else Bundle.EMPTY
+ def fromIntent(intent: Intent) = new TaskerSettings(if (intent.hasExtra(ApiIntent.EXTRA_BUNDLE))
+ intent.getBundleExtra(ApiIntent.EXTRA_BUNDLE) else Bundle.EMPTY)
- new TaskerSettings(bundle)
- }
-
- def fromBundle(bundle: Bundle): TaskerSettings = {
- new TaskerSettings(bundle)
- }
+ def fromBundle(bundle: Bundle) = new TaskerSettings(bundle)
}
class TaskerSettings(bundle: Bundle) {
import TaskerSettings._
- private val KEY_ACTION = "action"
- private val KEY_IS_START = "is_start"
- private val KEY_PROFILE_ID = "profile_id"
+ var switchOn = bundle.getBoolean(KEY_SWITCH_ON, true)
+ var profileId = bundle.getInt(KEY_PROFILE_ID, -1)
- var action: String = bundle.getString(KEY_ACTION, ACTION_UNKNOWN)
-
- var isStart: Boolean = _
- var profileId: Int = _
-
- action match {
- case ACTION_TOGGLE_SERVICE =>
- isStart = bundle.getBoolean(KEY_IS_START, true)
- case ACTION_SWITCH_PROFILE =>
- profileId = bundle.getInt(KEY_PROFILE_ID, -1)
- assert(profileId != -1, "profile id was wrong")
- case _ =>
- Log.w(Shadowsocks.TAG, s"unknown tasker action settings: $action")
- }
-
- def isEmpty = action == ACTION_UNKNOWN
-
- def toIntent(context: Context): Intent = {
+ def toIntent(context: Context) = {
val bundle = new Bundle()
-
- action match {
- case ACTION_TOGGLE_SERVICE =>
- bundle.putString(KEY_ACTION, action)
- bundle.putBoolean(KEY_IS_START, isStart)
- case ACTION_SWITCH_PROFILE =>
- bundle.putString(KEY_ACTION, action)
- bundle.putInt(KEY_PROFILE_ID, profileId)
- }
-
- val desc: String = action match {
- case ACTION_TOGGLE_SERVICE =>
- context.getString(R.string.turn_service_state,
- context.getString(if (isStart) R.string.state_on else R.string.state_off))
- case ACTION_SWITCH_PROFILE =>
- val profileName = ShadowsocksApplication.profileManager.getProfile(profileId) match {
- case Some(p) => p.name
- case None => context.getString(R.string.removed)
- }
- context.getString(R.string.switch_profile_to, profileName)
- }
-
- val intent: Intent = new Intent()
- intent.putExtra(ApiIntent.EXTRA_STRING_BLURB, desc)
- .putExtra(ApiIntent.EXTRA_BUNDLE, bundle)
+ if (!switchOn) bundle.putBoolean(KEY_SWITCH_ON, false)
+ if (profileId >= 0) bundle.putInt(KEY_PROFILE_ID, profileId)
+ new Intent().putExtra(ApiIntent.EXTRA_BUNDLE, bundle).putExtra(ApiIntent.EXTRA_STRING_BLURB,
+ ShadowsocksApplication.profileManager.getProfile(profileId) match {
+ case Some(p) => context.getString(if (switchOn) R.string.start_service else R.string.stop_service, p.name)
+ case None => context.getString(if (switchOn) R.string.start_service_default else R.string.stop)
+ })
}
}