Commit 29c5011c authored by Lucas Liu's avatar Lucas Liu Committed by Max Lv

Refine UI.

parent f1b1b64f
...@@ -42,7 +42,8 @@ libraryDependencies ++= Seq( ...@@ -42,7 +42,8 @@ libraryDependencies ++= Seq(
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01", "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01",
"com.j256.ormlite" % "ormlite-core" % "4.48", "com.j256.ormlite" % "ormlite-core" % "4.48",
"com.j256.ormlite" % "ormlite-android" % "4.48", "com.j256.ormlite" % "ormlite-android" % "4.48",
"com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2" "com.twofortyfouram" % "android-plugin-api-for-locale" % "1.0.2",
"com.github.clans" % "fab" % "1.6.2"
) )
proguardOptions in Android ++= Seq("-keep class com.github.shadowsocks.** { <init>(...); }", proguardOptions in Android ++= Seq("-keep class com.github.shadowsocks.** { <init>(...); }",
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 18H4V4h16v16zM18 6h-5c-1.1 0-2 .9-2 2v2.28c-.6.35-1 .98-1 1.72 0 1.1.9 2 2 2s2-.9 2-2c0-.74-.4-1.38-1-1.72V8h3v8H8V8h2V6H6v12h12V6z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"> android:layout_height="match_parent">
<include layout="@layout/toolbar_light_dark" /> <include layout="@layout/toolbar_light_dark" />
<android.support.design.widget.CoordinatorLayout android:layout_width="match_parent" <android.support.design.widget.CoordinatorLayout android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent">
android:layout_weight="1">
<android.support.v7.widget.RecyclerView android:id="@+id/profilesList" <android.support.v7.widget.RecyclerView android:id="@+id/profilesList"
app:layout_behavior="com.github.shadowsocks.widget.AutoPaddingBehavior" app:layout_behavior="com.github.shadowsocks.widget.AutoPaddingBehavior"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
<com.github.clans.fab.FloatingActionMenu
android:id="@+id/menu"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom|end"
android:layout_marginBottom="16dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
app:menu_colorNormal="@color/material_accent_500"
app:menu_colorPressed="@color/material_accent_700"
app:menu_colorRipple="@color/material_accent_500"
>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fab_manual_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_create"
app:fab_colorNormal="@color/material_accent_500"
app:fab_colorPressed="@color/material_accent_700"
app:fab_colorRipple="@color/material_accent_500"
app:fab_size="mini"
app:fab_label="@string/add_profile_methods_manual_settings"
/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fab_qrcode_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_camera_alt"
app:fab_colorNormal="@color/material_accent_500"
app:fab_colorPressed="@color/material_accent_700"
app:fab_colorRipple="@color/material_accent_500"
app:fab_size="mini"
app:fab_label="@string/add_profile_methods_scan_qr_code"
/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fab_nfc_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_nfc"
app:fab_colorNormal="@color/material_accent_500"
app:fab_colorPressed="@color/material_accent_700"
app:fab_colorRipple="@color/material_accent_500"
app:fab_size="mini"
app:fab_label="NFC"
/>
<com.github.clans.fab.FloatingActionButton
android:id="@+id/fab_import_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_content_paste"
app:fab_colorNormal="@color/material_accent_500"
app:fab_colorPressed="@color/material_accent_700"
app:fab_colorRipple="@color/material_accent_500"
app:fab_size="mini"
app:fab_label="@string/action_import"
/>
</com.github.clans.fab.FloatingActionMenu>
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>
</LinearLayout> </LinearLayout>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:title="@string/add_profile" <item android:id="@+id/action_export"
android:icon="@drawable/ic_content_add" android:title="@string/action_export"
android:alphabeticShortcut="a" android:alphabeticShortcut="e"
android:numericShortcut="0" app:showAsAction="never" />
app:showAsAction="always">
<menu>
<item android:id="@+id/scan_qr_code"
android:title="@string/add_profile_methods_scan_qr_code"
android:alphabeticShortcut="s"
android:numericShortcut="1"/>
<item android:id="@+id/manual_settings"
android:title="@string/add_profile_methods_manual_settings"
android:alphabeticShortcut="m"
android:numericShortcut="2"/>
<item android:id="@+id/action_import"
android:title="@string/action_import"
android:alphabeticShortcut="i"
android:numericShortcut="3"/>
<item android:id="@+id/action_export"
android:title="@string/action_export"
android:alphabeticShortcut="e"
android:numericShortcut="4"/>
</menu>
</item>
</menu> </menu>
...@@ -97,6 +97,8 @@ ...@@ -97,6 +97,8 @@
<string name="add_profile_dialog">为影梭添加此配置文件?</string> <string name="add_profile_dialog">为影梭添加此配置文件?</string>
<string name="add_profile_methods_scan_qr_code">扫描二维码</string> <string name="add_profile_methods_scan_qr_code">扫描二维码</string>
<string name="add_profile_methods_manual_settings">手动设置</string> <string name="add_profile_methods_manual_settings">手动设置</string>
<string name="add_profile_nfc_hint_title">使用 Android Beam (NFC) 来添加配置</string>
<string name="add_profile_nfc_hint">保持两台设备的屏幕亮起,在另外一台设备上,点击配置文件的分享按钮,将它们靠在一起(背靠背)。\n你也可以扫描 NFC 标签。</string>
<string-array name="route_entry"> <string-array name="route_entry">
<item>全局</item> <item>全局</item>
......
...@@ -117,6 +117,8 @@ ...@@ -117,6 +117,8 @@
<string name="add_profile_dialog">Add this Shadowsocks Profile?</string> <string name="add_profile_dialog">Add this Shadowsocks Profile?</string>
<string name="add_profile_methods_scan_qr_code">Scan QR code</string> <string name="add_profile_methods_scan_qr_code">Scan QR code</string>
<string name="add_profile_methods_manual_settings">Manual Settings</string> <string name="add_profile_methods_manual_settings">Manual Settings</string>
<string name="add_profile_nfc_hint_title">Use Android Beam (NFC) to add profile</string>
<string name="add_profile_nfc_hint">Keep both devices screen on, on the other device, click profile\'s share button, bring them together (back to back).\nYou also can scan a nfc tag.</string>
<string name="copy_url">Copy URL</string> <string name="copy_url">Copy URL</string>
<plurals name="removed"> <plurals name="removed">
<item quantity="one">Removed</item> <item quantity="one">Removed</item>
......
...@@ -17,6 +17,7 @@ import android.text.style.TextAppearanceSpan ...@@ -17,6 +17,7 @@ import android.text.style.TextAppearanceSpan
import android.text.{SpannableStringBuilder, Spanned, TextUtils} import android.text.{SpannableStringBuilder, Spanned, TextUtils}
import android.view.{LayoutInflater, MenuItem, View, ViewGroup} import android.view.{LayoutInflater, MenuItem, View, ViewGroup}
import android.widget.{CheckedTextView, ImageView, LinearLayout, Toast} import android.widget.{CheckedTextView, ImageView, LinearLayout, Toast}
import com.github.clans.fab.{FloatingActionMenu, FloatingActionButton}
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.database.Profile import com.github.shadowsocks.database.Profile
import com.github.shadowsocks.utils.{Key, Parser, TrafficMonitor, Utils} import com.github.shadowsocks.utils.{Key, Parser, TrafficMonitor, Utils}
...@@ -26,7 +27,7 @@ import net.glxn.qrgen.android.QRCode ...@@ -26,7 +27,7 @@ import net.glxn.qrgen.android.QRCode
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListener with ServiceBoundContext class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListener with ServiceBoundContext with View.OnClickListener
with CreateNdefMessageCallback { with CreateNdefMessageCallback {
private class ProfileViewHolder(val view: View) extends RecyclerView.ViewHolder(view) with View.OnClickListener { private class ProfileViewHolder(val view: View) extends RecyclerView.ViewHolder(view) with View.OnClickListener {
var item: Profile = _ var item: Profile = _
...@@ -162,6 +163,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe ...@@ -162,6 +163,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
private var selectedItem: ProfileViewHolder = _ private var selectedItem: ProfileViewHolder = _
private val handler = new Handler private val handler = new Handler
private var menu : FloatingActionMenu = _
private lazy val profilesAdapter = new ProfilesAdapter private lazy val profilesAdapter = new ProfilesAdapter
private var undoManager: UndoSnackbarManager[Profile] = _ private var undoManager: UndoSnackbarManager[Profile] = _
...@@ -187,6 +190,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe ...@@ -187,6 +190,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
toolbar.inflateMenu(R.menu.profile_manager_menu) toolbar.inflateMenu(R.menu.profile_manager_menu)
toolbar.setOnMenuItemClickListener(this) toolbar.setOnMenuItemClickListener(this)
initFab()
ShadowsocksApplication.profileManager.setProfileAddedListener(profilesAdapter.add) ShadowsocksApplication.profileManager.setProfileAddedListener(profilesAdapter.add)
val profilesList = findViewById(R.id.profilesList).asInstanceOf[RecyclerView] val profilesList = findViewById(R.id.profilesList).asInstanceOf[RecyclerView]
val layoutManager = new LinearLayoutManager(this) val layoutManager = new LinearLayoutManager(this)
...@@ -226,6 +231,19 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe ...@@ -226,6 +231,19 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
if (intent != null) handleShareIntent(intent) if (intent != null) handleShareIntent(intent)
} }
def initFab() {
menu = findViewById(R.id.menu).asInstanceOf[FloatingActionMenu]
menu.setClosedOnTouchOutside(true)
val manualAddFAB = findViewById(R.id.fab_manual_add).asInstanceOf[FloatingActionButton]
manualAddFAB.setOnClickListener(this)
val qrcodeAddFAB = findViewById(R.id.fab_qrcode_add).asInstanceOf[FloatingActionButton]
qrcodeAddFAB.setOnClickListener(this)
val nfcAddFAB = findViewById(R.id.fab_nfc_add).asInstanceOf[FloatingActionButton]
nfcAddFAB.setOnClickListener(this)
val importAddFAB = findViewById(R.id.fab_import_add).asInstanceOf[FloatingActionButton]
importAddFAB.setOnClickListener(this)
}
override def onResume() { override def onResume() {
super.onResume() super.onResume()
...@@ -237,6 +255,50 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe ...@@ -237,6 +255,50 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
handleShareIntent(intent) handleShareIntent(intent)
} }
override def onClick(v: View){
v.getId match {
case R.id.fab_manual_add =>
menu.toggle(true)
ShadowsocksApplication.profileManager.reload(-1)
ShadowsocksApplication.switchProfile(ShadowsocksApplication.profileManager.save.id)
finish
case R.id.fab_qrcode_add =>
menu.toggle(false)
val integrator = new IntentIntegrator(ProfileManagerActivity.this)
val list = new java.util.ArrayList(IntentIntegrator.TARGET_ALL_KNOWN)
list.add("tw.com.quickmark")
integrator.setTargetApplications(list)
integrator.initiateScan()
case R.id.fab_nfc_add =>
menu.toggle(true)
val dialog = new AlertDialog.Builder(ProfileManagerActivity.this)
.setCancelable(true)
.setPositiveButton(R.string.gotcha, null)
.setTitle(R.string.add_profile_nfc_hint_title)
.create()
if (!isNfcBeamEnabled) {
dialog.setMessage(getString(R.string.share_message_nfc_disabled))
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, getString(R.string.turn_on_nfc), ((_, _) =>
startActivity(new Intent(Settings.ACTION_NFC_SETTINGS))
): DialogInterface.OnClickListener)
} else {
dialog.setMessage(getString(R.string.add_profile_nfc_hint))
}
dialog.show
case R.id.fab_import_add =>
menu.toggle(true)
if (clipboard.hasPrimaryClip) {
val profiles = Parser.findAll(clipboard.getPrimaryClip.getItemAt(0).getText)
if (profiles.nonEmpty) {
profiles.foreach(ShadowsocksApplication.profileManager.createProfile)
Toast.makeText(this, R.string.action_import_msg, Toast.LENGTH_SHORT).show
return
}
}
Toast.makeText(this, R.string.action_import_err, Toast.LENGTH_SHORT).show
}
}
def updateNfcState() { def updateNfcState() {
isNfcAvailable = false isNfcAvailable = false
isNfcEnabled = false isNfcEnabled = false
...@@ -305,33 +367,14 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe ...@@ -305,33 +367,14 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
} }
} }
override def onBackPressed() {
if (menu.isOpened) menu.close(true) else super.onBackPressed()
}
def createNdefMessage(nfcEvent: NfcEvent) = def createNdefMessage(nfcEvent: NfcEvent) =
new NdefMessage(Array(new NdefRecord(NdefRecord.TNF_ABSOLUTE_URI, nfcShareItem, Array[Byte](), nfcShareItem))) new NdefMessage(Array(new NdefRecord(NdefRecord.TNF_ABSOLUTE_URI, nfcShareItem, Array[Byte](), nfcShareItem)))
def onMenuItemClick(item: MenuItem): Boolean = item.getItemId match { def onMenuItemClick(item: MenuItem): Boolean = item.getItemId match {
case R.id.scan_qr_code =>
val integrator = new IntentIntegrator(this)
val list = new java.util.ArrayList(IntentIntegrator.TARGET_ALL_KNOWN)
list.add("tw.com.quickmark")
integrator.setTargetApplications(list)
integrator.initiateScan()
true
case R.id.manual_settings =>
ShadowsocksApplication.profileManager.reload(-1)
ShadowsocksApplication.switchProfile(ShadowsocksApplication.profileManager.save.id)
finish
true
case R.id.action_import =>
if (clipboard.hasPrimaryClip) {
val profiles = Parser.findAll(clipboard.getPrimaryClip.getItemAt(0).getText)
if (profiles.nonEmpty) {
profiles.foreach(ShadowsocksApplication.profileManager.createProfile)
Toast.makeText(this, R.string.action_import_msg, Toast.LENGTH_SHORT).show
return true
}
}
Toast.makeText(this, R.string.action_import_err, Toast.LENGTH_SHORT).show
true
case R.id.action_export => case R.id.action_export =>
ShadowsocksApplication.profileManager.getAllProfiles match { ShadowsocksApplication.profileManager.getAllProfiles match {
case Some(profiles) => case Some(profiles) =>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment