Refine UI.
This commit is contained in:
@@ -42,7 +42,8 @@ libraryDependencies ++= Seq(
|
||||
"com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01",
|
||||
"com.j256.ormlite" % "ormlite-core" % "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>(...); }",
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -0,0 +1,9 @@
|
||||
<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>
|
||||
@@ -1,16 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="match_parent">
|
||||
<include layout="@layout/toolbar_light_dark" />
|
||||
<android.support.design.widget.CoordinatorLayout android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
android:layout_height="match_parent">
|
||||
<android.support.v7.widget.RecyclerView android:id="@+id/profilesList"
|
||||
app:layout_behavior="com.github.shadowsocks.widget.AutoPaddingBehavior"
|
||||
android:layout_width="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>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -1,28 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:title="@string/add_profile"
|
||||
android:icon="@drawable/ic_content_add"
|
||||
android:alphabeticShortcut="a"
|
||||
android:numericShortcut="0"
|
||||
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>
|
||||
<item android:id="@+id/action_export"
|
||||
android:title="@string/action_export"
|
||||
android:alphabeticShortcut="e"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
||||
|
||||
@@ -97,6 +97,8 @@
|
||||
<string name="add_profile_dialog">为影梭添加此配置文件?</string>
|
||||
<string name="add_profile_methods_scan_qr_code">扫描二维码</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">
|
||||
<item>全局</item>
|
||||
|
||||
@@ -117,6 +117,8 @@
|
||||
<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_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>
|
||||
<plurals name="removed">
|
||||
<item quantity="one">Removed</item>
|
||||
|
||||
@@ -17,6 +17,7 @@ import android.text.style.TextAppearanceSpan
|
||||
import android.text.{SpannableStringBuilder, Spanned, TextUtils}
|
||||
import android.view.{LayoutInflater, MenuItem, View, ViewGroup}
|
||||
import android.widget.{CheckedTextView, ImageView, LinearLayout, Toast}
|
||||
import com.github.clans.fab.{FloatingActionMenu, FloatingActionButton}
|
||||
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
|
||||
import com.github.shadowsocks.database.Profile
|
||||
import com.github.shadowsocks.utils.{Key, Parser, TrafficMonitor, Utils}
|
||||
@@ -26,7 +27,7 @@ import net.glxn.qrgen.android.QRCode
|
||||
|
||||
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 {
|
||||
private class ProfileViewHolder(val view: View) extends RecyclerView.ViewHolder(view) with View.OnClickListener {
|
||||
var item: Profile = _
|
||||
@@ -162,6 +163,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
|
||||
private var selectedItem: ProfileViewHolder = _
|
||||
private val handler = new Handler
|
||||
|
||||
private var menu : FloatingActionMenu = _
|
||||
|
||||
private lazy val profilesAdapter = new ProfilesAdapter
|
||||
private var undoManager: UndoSnackbarManager[Profile] = _
|
||||
|
||||
@@ -187,6 +190,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
|
||||
toolbar.inflateMenu(R.menu.profile_manager_menu)
|
||||
toolbar.setOnMenuItemClickListener(this)
|
||||
|
||||
initFab()
|
||||
|
||||
ShadowsocksApplication.profileManager.setProfileAddedListener(profilesAdapter.add)
|
||||
val profilesList = findViewById(R.id.profilesList).asInstanceOf[RecyclerView]
|
||||
val layoutManager = new LinearLayoutManager(this)
|
||||
@@ -226,6 +231,19 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
|
||||
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() {
|
||||
super.onResume()
|
||||
@@ -237,6 +255,50 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
|
||||
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() {
|
||||
isNfcAvailable = false
|
||||
isNfcEnabled = false
|
||||
@@ -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) =
|
||||
new NdefMessage(Array(new NdefRecord(NdefRecord.TNF_ABSOLUTE_URI, nfcShareItem, Array[Byte](), nfcShareItem)))
|
||||
|
||||
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 =>
|
||||
ShadowsocksApplication.profileManager.getAllProfiles match {
|
||||
case Some(profiles) =>
|
||||
|
||||
Reference in New Issue
Block a user