Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
Menu
Open sidebar
termapps
termoneplus
Commits
3d6fcb80
Commit
3d6fcb80
authored
Mar 14, 2018
by
Roumen Petrov
Browse files
new action bar management based on support toolbar
(ensure compatible look for API Level 7+)
parent
ac15ecdd
Changes
10
Hide whitespace changes
Inline
Side-by-side
term/src/main/AndroidManifest.xml
View file @
3d6fcb80
...
...
@@ -47,6 +47,7 @@
android:name=
"Term"
android:configChanges=
"keyboard|keyboardHidden|orientation"
android:launchMode=
"singleTask"
android:theme=
"@style/AppTheme.NoActionBar"
android:windowSoftInputMode=
"adjustResize|stateAlwaysVisible"
>
<intent-filter>
<action
android:name=
"android.intent.action.MAIN"
/>
...
...
term/src/main/java/com/termoneplus/TermActionBar.java
0 → 100644
View file @
3d6fcb80
/*
* Copyright (C) 2017 Roumen Petrov. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
com.termoneplus
;
import
android.support.v7.app.ActionBar
;
import
android.support.v7.app.AppCompatActivity
;
import
android.support.v7.widget.Toolbar
;
import
android.view.View
;
import
android.widget.AdapterView
;
import
android.widget.Spinner
;
import
jackpal.androidterm.R
;
import
jackpal.androidterm.WindowListAdapter
;
import
jackpal.androidterm.util.SessionList
;
/**
* An action bar for terminal emulator activity.
*/
public
class
TermActionBar
{
private
final
Toolbar
toolbar
;
private
final
Spinner
spinner
;
private
TermActionBar
(
AppCompatActivity
context
,
boolean
floating
)
{
toolbar
=
(
Toolbar
)
context
.
findViewById
(
R
.
id
.
toolbar
);
context
.
setSupportActionBar
(
toolbar
);
ActionBar
appbar
=
context
.
getSupportActionBar
();
if
(
appbar
!=
null
)
appbar
.
setDisplayShowTitleEnabled
(
false
);
spinner
=
(
Spinner
)
context
.
findViewById
(
R
.
id
.
spinner
);
if
(
floating
)
hide
();
}
public
static
TermActionBar
setTermContentView
(
AppCompatActivity
context
,
boolean
floating
)
{
if
(
floating
)
context
.
setContentView
(
R
.
layout
.
activity_term_floatbar
);
else
context
.
setContentView
(
R
.
layout
.
activity_term
);
return
new
TermActionBar
(
context
,
floating
);
}
public
void
setAdapter
(
WindowListAdapter
adapter
)
{
spinner
.
setAdapter
(
adapter
);
}
public
void
setOnItemSelectedListener
(
OnItemSelectedListener
listener
)
{
final
OnItemSelectedListener
callback
=
listener
;
AdapterView
.
OnItemSelectedListener
wrapper
=
new
AdapterView
.
OnItemSelectedListener
()
{
@Override
public
void
onItemSelected
(
AdapterView
<?>
parent
,
View
view
,
int
position
,
long
id
)
{
callback
.
onItemSelected
(
position
);
}
@Override
public
void
onNothingSelected
(
AdapterView
<?>
parent
)
{
}
};
spinner
.
setOnItemSelectedListener
(
wrapper
);
}
public
void
setSessions
(
SessionList
sessions
)
{
WindowListAdapter
adapter
=
(
WindowListAdapter
)
spinner
.
getAdapter
();
adapter
.
setSessions
(
sessions
);
}
public
void
setSelection
(
int
position
)
{
spinner
.
setSelection
(
position
);
}
public
boolean
isShowing
()
{
return
toolbar
.
getVisibility
()
==
View
.
VISIBLE
;
}
public
void
hide
()
{
toolbar
.
setVisibility
(
View
.
GONE
);
}
public
void
show
()
{
toolbar
.
setVisibility
(
View
.
VISIBLE
);
}
public
void
doToggleActionBar
()
{
if
(
isShowing
())
{
hide
();
}
else
{
show
();
}
}
public
interface
OnItemSelectedListener
{
void
onItemSelected
(
int
position
);
}
}
term/src/main/java/jackpal/androidterm/Term.java
View file @
3d6fcb80
...
...
@@ -17,8 +17,6 @@
package
jackpal.androidterm
;
import
android.app.Activity
;
import
android.app.AlertDialog
;
import
android.content.ActivityNotFoundException
;
import
android.content.BroadcastReceiver
;
import
android.content.ComponentName
;
...
...
@@ -37,6 +35,8 @@
import
android.os.IBinder
;
import
android.os.PowerManager
;
import
android.preference.PreferenceManager
;
import
android.support.v7.app.AlertDialog
;
import
android.support.v7.app.AppCompatActivity
;
import
android.text.TextUtils
;
import
android.util.DisplayMetrics
;
import
android.util.Log
;
...
...
@@ -56,6 +56,7 @@
import
android.widget.TextView
;
import
android.widget.Toast
;
import
com.termoneplus.TermActionBar
;
import
com.termoneplus.utils.WrapOpenURL
;
import
java.io.IOException
;
...
...
@@ -63,7 +64,6 @@
import
java.util.Arrays
;
import
java.util.Locale
;
import
jackpal.androidterm.compat.ActionBarCompat
;
import
jackpal.androidterm.compat.ActivityCompat
;
import
jackpal.androidterm.compat.AndroidCompat
;
import
jackpal.androidterm.compat.MenuItemCompat
;
...
...
@@ -80,7 +80,8 @@
* A terminal emulator activity.
*/
public
class
Term
extends
Activity
implements
UpdateCallback
,
SharedPreferences
.
OnSharedPreferenceChangeListener
{
public
class
Term
extends
AppCompatActivity
implements
UpdateCallback
,
SharedPreferences
.
OnSharedPreferenceChangeListener
{
public
static
final
int
REQUEST_CHOOSE_WINDOW
=
1
;
public
static
final
String
EXTRA_WINDOW_ID
=
"jackpal.androidterm.window_id"
;
/**
...
...
@@ -115,8 +116,8 @@ public class Term extends Activity implements UpdateCallback, SharedPreferences.
private
WifiManager
.
WifiLock
mWifiLock
;
private
int
mPendingPathBroadcasts
=
0
;
private
TermService
mTermService
;
private
ActionBar
Compat
mActionBar
;
private
int
mActionBarMode
=
TermSettings
.
ACTION_BAR_MODE_NONE
;
private
Term
ActionBar
mActionBar
;
private
int
mActionBarMode
;
private
WindowListAdapter
mWinListAdapter
;
private
boolean
mHaveFullHwKeyboard
=
false
;
/**
...
...
@@ -169,7 +170,7 @@ private boolean keyboardShortcuts(int keyCode, KeyEvent event) {
* Make sure the back button always leaves the application.
*/
private
boolean
backkeyInterceptor
(
int
keyCode
,
KeyEvent
event
)
{
if
(
keyCode
==
KeyEvent
.
KEYCODE_BACK
&&
mActionBarMode
==
TermSettings
.
ACTION_BAR_MODE_HIDES
&&
mActionBar
!=
null
&&
mActionBar
.
isShowing
())
{
if
(
keyCode
==
KeyEvent
.
KEYCODE_BACK
&&
mActionBarMode
==
TermSettings
.
ACTION_BAR_MODE_HIDES
&&
mActionBar
.
isShowing
())
{
/* We need to intercept the key event before the view sees it,
otherwise the view will handle it before we get it */
onKeyUp
(
keyCode
,
event
);
...
...
@@ -179,21 +180,6 @@ private boolean backkeyInterceptor(int keyCode, KeyEvent event) {
}
}
};
private
ActionBarCompat
.
OnNavigationListener
mWinListItemSelected
=
new
ActionBarCompat
.
OnNavigationListener
()
{
public
boolean
onNavigationItemSelected
(
int
position
,
long
id
)
{
int
oldPosition
=
mViewFlipper
.
getDisplayedChild
();
if
(
position
!=
oldPosition
)
{
if
(
position
>=
mViewFlipper
.
getChildCount
())
{
mViewFlipper
.
addView
(
createEmulatorView
(
mTermSessions
.
get
(
position
)));
}
mViewFlipper
.
setDisplayedChild
(
position
);
if
(
mActionBarMode
==
TermSettings
.
ACTION_BAR_MODE_HIDES
)
{
mActionBar
.
hide
();
}
}
return
true
;
}
};
private
BroadcastReceiver
mPathReceiver
=
new
BroadcastReceiver
()
{
public
void
onReceive
(
Context
context
,
Intent
intent
)
{
String
path
=
makePathFromBundle
(
getResultExtras
(
false
));
...
...
@@ -254,6 +240,7 @@ public void onCreate(Bundle icicle) {
final
SharedPreferences
mPrefs
=
PreferenceManager
.
getDefaultSharedPreferences
(
this
);
mSettings
=
new
TermSettings
(
getResources
(),
mPrefs
);
mPrefs
.
registerOnSharedPreferenceChangeListener
(
this
);
mActionBarMode
=
mSettings
.
actionBarMode
();
Intent
broadcast
=
new
Intent
(
ACTION_PATH_APPEND_BROADCAST
);
if
(
AndroidCompat
.
SDK
>=
12
)
{
...
...
@@ -270,24 +257,24 @@ public void onCreate(Bundle icicle) {
TSIntent
=
new
Intent
(
this
,
TermService
.
class
);
startService
(
TSIntent
);
if
(
AndroidCompat
.
SDK
>=
11
)
{
int
a
ctionBarMode
=
mSettings
.
actionBarMode
(
);
mActionBar
Mode
=
actionBarMode
;
if
(
AndroidCompat
.
V11ToV20
)
{
switch
(
actionBarMode
)
{
case
TermSettings
.
ACTION_BAR_MODE_ALWAYS_VISIBLE
:
setTheme
(
R
.
style
.
Theme_Holo
)
;
break
;
case
TermSettings
.
ACTION_BAR_MODE_HIDES
:
setTheme
(
R
.
style
.
Theme_Holo_ActionBarOverlay
);
break
;
mActionBar
=
TermActionBar
.
setTermContentView
(
this
,
mA
ctionBarMode
=
=
Ter
mSettings
.
ACTION_BAR_MODE_HIDES
);
mActionBar
.
setOnItemSelectedListener
(
new
TermActionBar
.
OnItemSelectedListener
()
{
@Override
public
void
onItemSelected
(
int
position
)
{
int
oldPosition
=
mViewFlipper
.
getDisplayedChild
();
if
(
position
==
oldPosition
)
return
;
if
(
position
>=
mViewFlipper
.
getChildCount
())
{
TermSession
session
=
mTermSessions
.
get
(
position
);
mViewFlipper
.
addView
(
createEmulatorView
(
session
))
;
}
mViewFlipper
.
setDisplayedChild
(
position
);
if
(
mActionBarMode
==
TermSettings
.
ACTION_BAR_MODE_HIDES
)
mActionBar
.
hide
();
}
}
else
{
mActionBarMode
=
TermSettings
.
ACTION_BAR_MODE_ALWAYS_VISIBLE
;
}
});
setContentView
(
R
.
layout
.
term_activity
);
mViewFlipper
=
(
TermViewFlipper
)
findViewById
(
VIEW_FLIPPER
);
Context
app
=
getApplicationContext
();
...
...
@@ -302,16 +289,6 @@ public void onCreate(Bundle icicle) {
}
mWifiLock
=
wm
.
createWifiLock
(
wifiLockMode
,
TermDebug
.
LOG_TAG
);
ActionBarCompat
actionBar
=
ActivityCompat
.
getActionBar
(
this
);
if
(
actionBar
!=
null
)
{
mActionBar
=
actionBar
;
actionBar
.
setNavigationMode
(
ActionBarCompat
.
NAVIGATION_MODE_LIST
);
actionBar
.
setDisplayOptions
(
0
,
ActionBarCompat
.
DISPLAY_SHOW_TITLE
);
if
(
mActionBarMode
==
TermSettings
.
ACTION_BAR_MODE_HIDES
)
{
actionBar
.
hide
();
}
}
mHaveFullHwKeyboard
=
checkHaveFullHwKeyboard
(
getResources
().
getConfiguration
());
updatePrefs
();
...
...
@@ -381,15 +358,11 @@ private void populateViewFlipper() {
}
private
void
populateWindowList
()
{
if
(
mActionBar
==
null
)
{
// Not needed
return
;
}
if
(
mTermSessions
!=
null
)
{
if
(
mWinListAdapter
==
null
)
{
mWinListAdapter
=
new
WindowListActionBarAdapter
(
mTermSessions
);
mActionBar
.
set
ListNavigationCallbacks
(
mWinListAdapter
,
mWinListItemSelected
);
mActionBar
.
set
Adapter
(
mWinListAdapter
);
}
else
{
mWinListAdapter
.
setSessions
(
mTermSessions
);
}
...
...
@@ -480,7 +453,7 @@ private void updatePrefs() {
WindowManager
.
LayoutParams
params
=
win
.
getAttributes
();
final
int
FULLSCREEN
=
WindowManager
.
LayoutParams
.
FLAG_FULLSCREEN
;
int
desiredFlag
=
mSettings
.
showStatusBar
()
?
0
:
FULLSCREEN
;
if
(
desiredFlag
!=
(
params
.
flags
&
FULLSCREEN
)
||
(
AndroidCompat
.
SDK
>=
11
&&
mActionBarMode
!=
mSettings
.
actionBarMode
()))
{
if
(
desiredFlag
!=
(
params
.
flags
&
FULLSCREEN
)
||
(
mActionBarMode
!=
mSettings
.
actionBarMode
()))
{
if
(
mAlreadyStarted
)
{
// Can't switch to/from fullscreen after
// starting the activity.
...
...
@@ -488,9 +461,7 @@ private void updatePrefs() {
}
else
{
win
.
setFlags
(
desiredFlag
,
FULLSCREEN
);
if
(
mActionBarMode
==
TermSettings
.
ACTION_BAR_MODE_HIDES
)
{
if
(
mActionBar
!=
null
)
{
mActionBar
.
hide
();
}
mActionBar
.
hide
();
}
}
}
...
...
@@ -796,7 +767,7 @@ public boolean onContextItemSelected(MenuItem item) {
public
boolean
onKeyUp
(
int
keyCode
,
KeyEvent
event
)
{
switch
(
keyCode
)
{
case
KeyEvent
.
KEYCODE_BACK
:
if
(
mActionBarMode
==
TermSettings
.
ACTION_BAR_MODE_HIDES
&&
mActionBar
!=
null
&&
mActionBar
.
isShowing
())
{
if
(
mActionBarMode
==
TermSettings
.
ACTION_BAR_MODE_HIDES
&&
mActionBar
.
isShowing
())
{
mActionBar
.
hide
();
return
true
;
}
...
...
@@ -813,7 +784,7 @@ public boolean onKeyUp(int keyCode, KeyEvent event) {
return
false
;
}
case
KeyEvent
.
KEYCODE_MENU
:
if
(
mActionBar
!=
null
&&
!
mActionBar
.
isShowing
())
{
if
(!
mActionBar
.
isShowing
())
{
mActionBar
.
show
();
return
true
;
}
else
{
...
...
@@ -976,28 +947,8 @@ private void doToggleWifiLock() {
ActivityCompat
.
invalidateOptionsMenu
(
this
);
}
private
void
doToggleActionBar
()
{
ActionBarCompat
bar
=
mActionBar
;
if
(
bar
==
null
)
{
return
;
}
if
(
bar
.
isShowing
())
{
bar
.
hide
();
}
else
{
bar
.
show
();
}
}
private
void
doUIToggle
(
int
x
,
int
y
,
int
width
,
int
height
)
{
switch
(
mActionBarMode
)
{
case
TermSettings
.
ACTION_BAR_MODE_NONE
:
if
(
AndroidCompat
.
SDK
>=
11
&&
(
mHaveFullHwKeyboard
||
y
<
height
/
2
))
{
openOptionsMenu
();
return
;
}
else
{
doToggleSoftKeyboard
();
}
break
;
case
TermSettings
.
ACTION_BAR_MODE_ALWAYS_VISIBLE
:
if
(!
mHaveFullHwKeyboard
)
{
doToggleSoftKeyboard
();
...
...
@@ -1005,7 +956,7 @@ private void doUIToggle(int x, int y, int width, int height) {
break
;
case
TermSettings
.
ACTION_BAR_MODE_HIDES
:
if
(
mHaveFullHwKeyboard
||
y
<
height
/
2
)
{
doToggleActionBar
();
mActionBar
.
doToggleActionBar
();
return
;
}
else
{
doToggleSoftKeyboard
();
...
...
@@ -1017,7 +968,7 @@ private void doUIToggle(int x, int y, int width, int height) {
private
void
synchronizeActionBar
()
{
int
position
=
mViewFlipper
.
getDisplayedChild
();
mActionBar
.
setSelect
edNavigationItem
(
position
);
mActionBar
.
setSelect
ion
(
position
);
}
private
class
WindowListActionBarAdapter
extends
WindowListAdapter
implements
UpdateCallback
{
...
...
term/src/main/java/jackpal/androidterm/TermPreferences.java
View file @
3d6fcb80
...
...
@@ -36,16 +36,6 @@ protected void onCreate(Bundle savedInstanceState) {
// Load the preferences from an XML resource
addPreferencesFromResource
(
R
.
xml
.
preferences
);
// Remove the action bar pref on older platforms without an action bar
if
(
AndroidCompat
.
SDK
<
11
)
{
Preference
actionBarPref
=
findPreference
(
ACTIONBAR_KEY
);
PreferenceCategory
screenCategory
=
(
PreferenceCategory
)
findPreference
(
CATEGORY_SCREEN_KEY
);
if
((
actionBarPref
!=
null
)
&&
(
screenCategory
!=
null
))
{
screenCategory
.
removePreference
(
actionBarPref
);
}
}
// Display up indicator on action bar home button
if
(
AndroidCompat
.
V11ToV20
)
{
ActionBarCompat
bar
=
ActivityCompat
.
getActionBar
(
this
);
...
...
term/src/main/java/jackpal/androidterm/TermViewFlipper.java
View file @
3d6fcb80
...
...
@@ -77,7 +77,8 @@ private void commonConstructor(Context context) {
this
.
context
=
context
;
callbacks
=
new
LinkedList
<
UpdateCallback
>();
updateVisibleRect
();
if
(!
isInEditMode
())
updateVisibleRect
();
Rect
visible
=
mVisibleRect
;
mChildParams
=
new
LayoutParams
(
visible
.
width
(),
visible
.
height
(),
Gravity
.
TOP
|
Gravity
.
LEFT
);
...
...
term/src/main/java/jackpal/androidterm/util/TermSettings.java
View file @
3d6fcb80
...
...
@@ -109,7 +109,6 @@ public class TermSettings {
{
LINUX_CONSOLE_WHITE
,
BLACK
}
};
public
static
final
int
ACTION_BAR_MODE_NONE
=
0
;
public
static
final
int
ACTION_BAR_MODE_ALWAYS_VISIBLE
=
1
;
public
static
final
int
ACTION_BAR_MODE_HIDES
=
2
;
private
static
final
int
ACTION_BAR_MODE_MAX
=
2
;
...
...
term/src/main/res/layout/activity_term.xml
0 → 100644
View file @
3d6fcb80
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2017 Roumen Petrov. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:orientation=
"vertical"
>
<android.support.design.widget.AppBarLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"@android:color/transparent"
android:theme=
"@style/AppTheme.AppBarOverlay"
>
<android.support.v7.widget.Toolbar
android:id=
"@+id/toolbar"
android:layout_width=
"match_parent"
android:layout_height=
"?attr/actionBarSize"
android:background=
"?attr/colorPrimary"
app:logo=
"@mipmap/ic_launcher"
app:popupTheme=
"@style/AppTheme.PopupOverlay"
>
<Spinner
android:id=
"@+id/spinner"
android:layout_width=
"wrap_content"
android:layout_height=
"match_parent"
/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<jackpal.androidterm.TermViewFlipper
android:id=
"@+id/view_flipper"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"@android:color/black"
/>
</LinearLayout>
term/src/main/res/layout/activity_term_floatbar.xml
0 → 100644
View file @
3d6fcb80
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2017 Roumen Petrov. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<FrameLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<jackpal.androidterm.TermViewFlipper
android:id=
"@+id/view_flipper"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"@android:color/black"
/>
<android.support.design.widget.AppBarLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_gravity=
"top"
android:background=
"@android:color/transparent"
android:theme=
"@style/AppTheme.AppBarOverlay"
>
<android.support.v7.widget.Toolbar
android:id=
"@+id/toolbar"
android:layout_width=
"match_parent"
android:layout_height=
"?attr/actionBarSize"
android:background=
"@color/floatToolbar"
app:logo=
"@mipmap/ic_launcher"
app:popupTheme=
"@style/AppTheme.PopupOverlay"
>
<Spinner
android:id=
"@+id/spinner"
android:layout_width=
"wrap_content"
android:layout_height=
"match_parent"
/>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
</FrameLayout>
term/src/main/res/values/colors.xml
View file @
3d6fcb80
...
...
@@ -18,4 +18,5 @@
<color
name=
"colorPrimary"
>
#607D8B
</color>
<color
name=
"colorPrimaryDark"
>
#455A64
</color>
<color
name=
"colorAccent"
>
#8BC34A
</color>
<color
name=
"floatToolbar"
>
#A0607D8B
</color>
</resources>
term/src/main/res/xml/preferences.xml
View file @
3d6fcb80
...
...
@@ -34,7 +34,7 @@
android:key=
"actionbar"
android:defaultValue=
"@integer/pref_actionbar_default"
android:title=
"@string/title_actionbar_preference"
android:summary=
"@string/summary_actionbar_preference"
android:summary=
"@string/summary_actionbar_preference
_compat
"
android:entries=
"@array/entries_actionbar_preference"
android:entryValues=
"@array/entryvalues_actionbar_preference"
android:dialogTitle=
"@string/dialog_title_actionbar_preference"
/>
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment