Merge branch 'master' into menu-updates
1
BUILD.md
@ -46,6 +46,7 @@ This can either be entered directly into your shell session before you build or
|
||||
|
||||
The path it needs to be set to will depend on where and how Qt5 was installed. e.g.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10.1/gcc_64/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/qt/5.10.1/clang_64/lib/cmake/
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.10.1/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
|
||||
|
@ -6,13 +6,20 @@ Please read the [general build guide](BUILD.md) for information on dependencies
|
||||
|
||||
Should you choose not to install Qt5 via a package manager that handles dependencies for you, you may be missing some Qt5 dependencies. On Ubuntu, for example, the following additional packages are required:
|
||||
|
||||
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev
|
||||
libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev zlib1g-dev
|
||||
|
||||
## Ubuntu 16.04 specific build guide
|
||||
## Ubuntu 16.04/18.04 specific build guide
|
||||
|
||||
### Ubuntu 18.04 only
|
||||
Add the universe repository:
|
||||
_(This is not enabled by default on the server edition)_
|
||||
```bash
|
||||
sudo add-apt-repository universe
|
||||
sudo apt-get update
|
||||
```
|
||||
|
||||
### Prepare environment
|
||||
hifiqt5.10.1
|
||||
Install qt:
|
||||
Install Qt 5.10.1:
|
||||
```bash
|
||||
wget http://debian.highfidelity.com/pool/h/hi/hifiqt5.10.1_5.10.1_amd64.deb
|
||||
sudo dpkg -i hifiqt5.10.1_5.10.1_amd64.deb
|
||||
@ -20,19 +27,20 @@ sudo dpkg -i hifiqt5.10.1_5.10.1_amd64.deb
|
||||
|
||||
Install build dependencies:
|
||||
```bash
|
||||
sudo apt-get install libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev
|
||||
sudo apt-get install libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack0 libjack-dev libxrandr-dev libudev-dev libssl-dev zlib1g-dev
|
||||
```
|
||||
|
||||
To compile interface in a server you must install:
|
||||
```bash
|
||||
sudo apt -y install libpulse0 libnss3 libnspr4 libfontconfig1 libxcursor1 libxcomposite1 libxtst6 libxslt1.1
|
||||
sudo apt-get -y install libpulse0 libnss3 libnspr4 libfontconfig1 libxcursor1 libxcomposite1 libxtst6 libxslt1.1
|
||||
```
|
||||
|
||||
Install build tools:
|
||||
```bash
|
||||
sudo apt install cmake
|
||||
sudo apt-get install cmake
|
||||
```
|
||||
|
||||
|
||||
### Get code and checkout the tag you need
|
||||
|
||||
Clone this repository:
|
||||
@ -48,12 +56,7 @@ git tags
|
||||
|
||||
Then checkout last tag with:
|
||||
```bash
|
||||
git checkout tags/RELEASE-6819
|
||||
```
|
||||
|
||||
Or go to the highfidelity download page (https://highfidelity.com/download) to get the release version. For example, if there is a BETA 6731 type:
|
||||
```bash
|
||||
git checkout tags/RELEASE-6731
|
||||
git checkout tags/v0.71.0
|
||||
```
|
||||
|
||||
### Compiling
|
||||
@ -66,15 +69,20 @@ cd hifi/build
|
||||
|
||||
Prepare makefiles:
|
||||
```bash
|
||||
cmake -DQT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10/gcc_64/lib/cmake ..
|
||||
cmake -DQT_CMAKE_PREFIX_PATH=/usr/local/Qt5.10.1/5.10.1/gcc_64/lib/cmake ..
|
||||
```
|
||||
|
||||
Start compilation and get a cup of coffee:
|
||||
Start compilation of the server and get a cup of coffee:
|
||||
```bash
|
||||
make domain-server assignment-client interface
|
||||
make domain-server assignment-client
|
||||
```
|
||||
|
||||
In a server does not make sense to compile interface
|
||||
To compile interface:
|
||||
```bash
|
||||
make interface
|
||||
```
|
||||
|
||||
In a server, it does not make sense to compile interface
|
||||
|
||||
### Running the software
|
||||
|
||||
@ -93,4 +101,4 @@ Running interface:
|
||||
./interface/interface
|
||||
```
|
||||
|
||||
Go to localhost in running interface.
|
||||
Go to localhost in the running interface.
|
||||
|
@ -133,6 +133,10 @@ dependencies {
|
||||
|
||||
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
|
||||
implementation 'com.android.support:design:26.1.0'
|
||||
compile 'com.android.support:support-v4:26.1.0'
|
||||
compile 'com.android.support:appcompat-v7:26.1.0'
|
||||
compile 'com.android.support:support-vector-drawable:26.1.0'
|
||||
|
||||
implementation 'com.android.support:appcompat-v7:26.1.0'
|
||||
compile 'com.android.support:recyclerview-v7:26.1.0'
|
||||
compile 'com.android.support:cardview-v7:26.1.0'
|
||||
|
@ -9,6 +9,7 @@
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
|
||||
<uses-feature android:name="android.hardware.sensor.accelerometer" android:required="true"/>
|
||||
<uses-feature android:name="android.hardware.sensor.gyroscope" android:required="true"/>
|
||||
|
||||
@ -75,6 +76,15 @@
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":breakpad_uploader"/>
|
||||
|
||||
<receiver
|
||||
android:name=".receiver.HeadsetStateReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.HEADSET_PLUG" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
<uses-feature android:name="android.software.vr.mode" android:required="true"/>
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
QAndroidJniObject __interfaceActivity;
|
||||
QAndroidJniObject __loginCompletedListener;
|
||||
QAndroidJniObject __signupCompletedListener;
|
||||
QAndroidJniObject __loadCompleteListener;
|
||||
QAndroidJniObject __usernameChangedListener;
|
||||
void tempMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
@ -156,7 +157,7 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCrea
|
||||
JavaVM* jvm;
|
||||
env->GetJavaVM(&jvm);
|
||||
|
||||
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [jvm](const QString& a, const bool backToScene, QList<QString> args) {
|
||||
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [jvm](const QString& a, const bool backToScene, QMap<QString, QString> args) {
|
||||
JNIEnv* myNewEnv;
|
||||
JavaVMAttachArgs jvmArgs;
|
||||
jvmArgs.version = JNI_VERSION_1_6; // choose your JNI version
|
||||
@ -182,9 +183,11 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCrea
|
||||
jmethodID mapClassConstructor = myNewEnv->GetMethodID(hashMapClass, "<init>", "()V");
|
||||
jobject hashmap = myNewEnv->NewObject(hashMapClass, mapClassConstructor);
|
||||
jmethodID mapClassPut = myNewEnv->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
for (const QString& arg: args) {
|
||||
QAndroidJniObject jArg = QAndroidJniObject::fromString(arg);
|
||||
myNewEnv->CallObjectMethod(hashmap, mapClassPut, QAndroidJniObject::fromString("url").object<jstring>(), jArg.object<jstring>());
|
||||
QMap<QString, QString>::iterator i;
|
||||
for (i = args.begin(); i != args.end(); ++i) {
|
||||
QAndroidJniObject jKey = QAndroidJniObject::fromString(i.key());
|
||||
QAndroidJniObject jValue = QAndroidJniObject::fromString(i.value());
|
||||
myNewEnv->CallObjectMethod(hashmap, mapClassPut, jKey.object<jstring>(), jValue.object<jstring>());
|
||||
}
|
||||
__interfaceActivity.callMethod<void>("openAndroidActivity", "(Ljava/lang/String;ZLjava/util/HashMap;)V", string.object<jstring>(), jBackToScene, hashmap);
|
||||
if (attachedHere) {
|
||||
@ -255,6 +258,24 @@ JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_fragment_HomeFragme
|
||||
return env->NewStringUTF(lastLocation.toString().toLatin1().data());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeCancelLogin(JNIEnv *env, jobject instance) {
|
||||
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
QObject::disconnect(accountManager.data(), &AccountManager::loginComplete, nullptr, nullptr);
|
||||
QObject::disconnect(accountManager.data(), &AccountManager::loginFailed, nullptr, nullptr);
|
||||
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeCancelLogin(JNIEnv *env,
|
||||
jobject instance) {
|
||||
|
||||
Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeCancelLogin(env, instance);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *env, jobject instance,
|
||||
jstring username_, jstring password_,
|
||||
@ -273,23 +294,90 @@ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(JNIEnv *en
|
||||
|
||||
QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
|
||||
jboolean jSuccess = (jboolean) true;
|
||||
__loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
|
||||
if (__loginCompletedListener.isValid()) {
|
||||
__loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() {
|
||||
jboolean jSuccess = (jboolean) false;
|
||||
__loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
|
||||
if (__loginCompletedListener.isValid()) {
|
||||
__loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(accountManager.data(), &AccountManager::usernameChanged, [](const QString& username) {
|
||||
QAndroidJniObject string = QAndroidJniObject::fromString(username);
|
||||
__usernameChangedListener.callMethod<void>("handleUsernameChanged", "(Ljava/lang/String;)V", string.object<jstring>());
|
||||
if (__usernameChangedListener.isValid()) {
|
||||
__usernameChangedListener.callMethod<void>("handleUsernameChanged", "(Ljava/lang/String;)V", string.object<jstring>());
|
||||
}
|
||||
});
|
||||
|
||||
QMetaObject::invokeMethod(accountManager.data(), "requestAccessToken",
|
||||
Q_ARG(const QString&, username), Q_ARG(const QString&, password));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeLogin(JNIEnv *env,
|
||||
jobject instance,
|
||||
jstring username_,
|
||||
jstring password_,
|
||||
jobject usernameChangedListener) {
|
||||
Java_io_highfidelity_hifiinterface_fragment_LoginFragment_nativeLogin(env, instance, username_, password_, usernameChangedListener);
|
||||
}
|
||||
|
||||
JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeInitAfterAppLoaded(JNIEnv* env, jobject obj) {
|
||||
AndroidHelper::instance().moveToThread(qApp->thread());
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeSignup(JNIEnv *env, jobject instance,
|
||||
jstring email_, jstring username_,
|
||||
jstring password_) {
|
||||
|
||||
const char *c_email = env->GetStringUTFChars(email_, 0);
|
||||
const char *c_username = env->GetStringUTFChars(username_, 0);
|
||||
const char *c_password = env->GetStringUTFChars(password_, 0);
|
||||
QString email = QString(c_email);
|
||||
QString username = QString(c_username);
|
||||
QString password = QString(c_password);
|
||||
env->ReleaseStringUTFChars(email_, c_email);
|
||||
env->ReleaseStringUTFChars(username_, c_username);
|
||||
env->ReleaseStringUTFChars(password_, c_password);
|
||||
|
||||
__signupCompletedListener = QAndroidJniObject(instance);
|
||||
|
||||
// disconnect any previous callback
|
||||
QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupCompleted, nullptr, nullptr);
|
||||
QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupFailed, nullptr, nullptr);
|
||||
|
||||
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::handleSignupCompleted, []() {
|
||||
jboolean jSuccess = (jboolean) true;
|
||||
if (__signupCompletedListener.isValid()) {
|
||||
__signupCompletedListener.callMethod<void>("handleSignupCompleted", "()V", jSuccess);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(&AndroidHelper::instance(), &AndroidHelper::handleSignupFailed, [](QString errorString) {
|
||||
jboolean jSuccess = (jboolean) false;
|
||||
jstring jError = QAndroidJniObject::fromString(errorString).object<jstring>();
|
||||
if (__signupCompletedListener.isValid()) {
|
||||
QAndroidJniObject string = QAndroidJniObject::fromString(errorString);
|
||||
__signupCompletedListener.callMethod<void>("handleSignupFailed", "(Ljava/lang/String;)V", string.object<jstring>());
|
||||
}
|
||||
});
|
||||
|
||||
AndroidHelper::instance().signup(email, username, password);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_SignupFragment_nativeCancelSignup(JNIEnv *env, jobject instance) {
|
||||
QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupCompleted, nullptr, nullptr);
|
||||
QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupFailed, nullptr, nullptr);
|
||||
|
||||
__signupCompletedListener = nullptr;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_FriendsFragment_nativeIsLoggedIn(JNIEnv *env, jobject instance) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
@ -355,5 +443,51 @@ JNIEXPORT void Java_io_highfidelity_hifiinterface_WebViewActivity_nativeProcessU
|
||||
AndroidHelper::instance().processURL(QString::fromUtf8(nativeString));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_SettingsFragment_updateHifiSetting(JNIEnv *env,
|
||||
jobject instance,
|
||||
jstring group_,
|
||||
jstring key_,
|
||||
jboolean value_) {
|
||||
const char *c_group = env->GetStringUTFChars(group_, 0);
|
||||
const char *c_key = env->GetStringUTFChars(key_, 0);
|
||||
|
||||
const QString group = QString::fromUtf8(c_group);
|
||||
const QString key = QString::fromUtf8(c_key);
|
||||
|
||||
env->ReleaseStringUTFChars(group_, c_group);
|
||||
env->ReleaseStringUTFChars(key_, c_key);
|
||||
|
||||
bool value = value_;
|
||||
|
||||
Setting::Handle<bool> setting { QStringList() << group << key , !value };
|
||||
setting.set(value);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_io_highfidelity_hifiinterface_fragment_SettingsFragment_getHifiSettingBoolean(JNIEnv *env,
|
||||
jobject instance,
|
||||
jstring group_,
|
||||
jstring key_,
|
||||
jboolean defaultValue) {
|
||||
const char *c_group = env->GetStringUTFChars(group_, 0);
|
||||
const char *c_key = env->GetStringUTFChars(key_, 0);
|
||||
|
||||
const QString group = QString::fromUtf8(c_group);
|
||||
const QString key = QString::fromUtf8(c_key);
|
||||
|
||||
env->ReleaseStringUTFChars(group_, c_group);
|
||||
env->ReleaseStringUTFChars(key_, c_key);
|
||||
|
||||
Setting::Handle<bool> setting { QStringList() << group << key , defaultValue};
|
||||
return setting.get();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_io_highfidelity_hifiinterface_receiver_HeadsetStateReceiver_notifyHeadsetOn(JNIEnv *env,
|
||||
jobject instance,
|
||||
jboolean pluggedIn) {
|
||||
AndroidHelper::instance().notifyHeadsetOn(pluggedIn);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ package io.highfidelity.hifiinterface;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -38,8 +39,10 @@ import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.highfidelity.hifiinterface.fragment.WebViewFragment;
|
||||
import io.highfidelity.hifiinterface.receiver.HeadsetStateReceiver;
|
||||
|
||||
/*import com.google.vr.cardboard.DisplaySynchronizer;
|
||||
import com.google.vr.cardboard.DisplayUtils;
|
||||
@ -55,6 +58,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
|
||||
private static final int NORMAL_DPI = 160;
|
||||
|
||||
private Vibrator mVibrator;
|
||||
private HeadsetStateReceiver headsetStateReceiver;
|
||||
|
||||
//public static native void handleHifiURL(String hifiURLString);
|
||||
private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
|
||||
@ -65,6 +69,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
|
||||
private native void nativeEnterBackground();
|
||||
private native void nativeEnterForeground();
|
||||
private native long nativeOnExitVr();
|
||||
private native void nativeInitAfterAppLoaded();
|
||||
|
||||
private AssetManager assetManager;
|
||||
|
||||
@ -151,6 +156,8 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
|
||||
layoutParams.resolveLayoutDirection(View.LAYOUT_DIRECTION_RTL);
|
||||
qtLayout.addView(webSlidingDrawer, layoutParams);
|
||||
webSlidingDrawer.setVisibility(View.GONE);
|
||||
|
||||
headsetStateReceiver = new HeadsetStateReceiver();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -161,6 +168,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
|
||||
} else {
|
||||
nativeEnterBackground();
|
||||
}
|
||||
unregisterReceiver(headsetStateReceiver);
|
||||
//gvrApi.pauseTracking();
|
||||
}
|
||||
|
||||
@ -183,6 +191,7 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
|
||||
nativeEnterForeground();
|
||||
surfacesWorkaround();
|
||||
keepInterfaceRunning = false;
|
||||
registerReceiver(headsetStateReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
|
||||
//gvrApi.resumeTracking();
|
||||
}
|
||||
|
||||
@ -296,14 +305,22 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
|
||||
switch (activityName) {
|
||||
case "Home":
|
||||
case "Privacy Policy":
|
||||
case "Login": {
|
||||
nativeBeforeEnterBackground();
|
||||
Intent intent = new Intent(this, MainActivity.class);
|
||||
intent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName);
|
||||
intent.putExtra(MainActivity.EXTRA_BACK_TO_SCENE, backToScene);
|
||||
startActivity(intent);
|
||||
break;
|
||||
}
|
||||
case "Login":
|
||||
nativeBeforeEnterBackground();
|
||||
Intent loginIntent = new Intent(this, MainActivity.class);
|
||||
loginIntent.putExtra(MainActivity.EXTRA_FRAGMENT, activityName);
|
||||
loginIntent.putExtra(MainActivity.EXTRA_BACK_TO_SCENE, backToScene);
|
||||
if (args != null && args.containsKey(DOMAIN_URL)) {
|
||||
loginIntent.putExtra(DOMAIN_URL, (String) args.get(DOMAIN_URL));
|
||||
}
|
||||
startActivity(loginIntent);
|
||||
break;
|
||||
case "WebView":
|
||||
runOnUiThread(() -> {
|
||||
webSlidingDrawer.setVisibility(View.VISIBLE);
|
||||
@ -335,6 +352,9 @@ public class InterfaceActivity extends QtActivity implements WebViewFragment.OnW
|
||||
if (nativeEnterBackgroundCallEnqueued) {
|
||||
nativeEnterBackground();
|
||||
}
|
||||
runOnUiThread(() -> {
|
||||
nativeInitAfterAppLoaded();
|
||||
});
|
||||
}
|
||||
|
||||
public void performHapticFeedback(int duration) {
|
||||
|
@ -29,21 +29,29 @@ import android.widget.TextView;
|
||||
import com.squareup.picasso.Callback;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.highfidelity.hifiinterface.fragment.FriendsFragment;
|
||||
import io.highfidelity.hifiinterface.fragment.HomeFragment;
|
||||
import io.highfidelity.hifiinterface.fragment.LoginFragment;
|
||||
import io.highfidelity.hifiinterface.fragment.PolicyFragment;
|
||||
import io.highfidelity.hifiinterface.task.DownloadProfileImageTask;
|
||||
import io.highfidelity.hifiinterface.fragment.SettingsFragment;
|
||||
import io.highfidelity.hifiinterface.fragment.SignedInFragment;
|
||||
import io.highfidelity.hifiinterface.fragment.SignupFragment;import io.highfidelity.hifiinterface.task.DownloadProfileImageTask;
|
||||
|
||||
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener,
|
||||
LoginFragment.OnLoginInteractionListener,
|
||||
HomeFragment.OnHomeInteractionListener,
|
||||
FriendsFragment.OnHomeInteractionListener {
|
||||
FriendsFragment.OnHomeInteractionListener,
|
||||
SignupFragment.OnSignupInteractionListener,
|
||||
SignedInFragment.OnSignedInInteractionListener {
|
||||
|
||||
private static final int PROFILE_PICTURE_PLACEHOLDER = R.drawable.default_profile_avatar;
|
||||
public static final String DEFAULT_FRAGMENT = "Home";
|
||||
public static final String EXTRA_FRAGMENT = "fragment";
|
||||
public static final String EXTRA_BACK_TO_SCENE = "backToScene";
|
||||
public static final String EXTRA_BACK_TO_URL = "url";
|
||||
|
||||
private String TAG = "HighFidelity";
|
||||
|
||||
@ -61,6 +69,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
private MenuItem mPeopleMenuItem;
|
||||
|
||||
private boolean backToScene;
|
||||
private String backToUrl;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@ -80,6 +89,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
|
||||
mPeopleMenuItem = mNavigationView.getMenu().findItem(R.id.action_people);
|
||||
|
||||
updateDebugMenu(mNavigationView.getMenu());
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
toolbar.setTitleTextAppearance(this, R.style.HomeActionBarTitleStyle);
|
||||
setSupportActionBar(toolbar);
|
||||
@ -102,8 +113,17 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
loadFragment(DEFAULT_FRAGMENT);
|
||||
}
|
||||
|
||||
if (getIntent().hasExtra(EXTRA_BACK_TO_SCENE)) {
|
||||
backToScene = getIntent().getBooleanExtra(EXTRA_BACK_TO_SCENE, false);
|
||||
backToScene = getIntent().getBooleanExtra(EXTRA_BACK_TO_SCENE, false);
|
||||
backToUrl = getIntent().getStringExtra(EXTRA_BACK_TO_URL);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDebugMenu(Menu menu) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
for (int i=0; i < menu.size(); i++) {
|
||||
if (menu.getItem(i).getItemId() == R.id.action_debug_settings) {
|
||||
menu.getItem(i).setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -130,28 +150,44 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
|
||||
private void loadHomeFragment(boolean addToBackStack) {
|
||||
Fragment fragment = HomeFragment.newInstance();
|
||||
loadFragment(fragment, getString(R.string.home), getString(R.string.tagFragmentHome), addToBackStack);
|
||||
loadFragment(fragment, getString(R.string.home), getString(R.string.tagFragmentHome), addToBackStack, true);
|
||||
}
|
||||
|
||||
private void loadLoginFragment() {
|
||||
Fragment fragment = LoginFragment.newInstance();
|
||||
loadFragment(fragment, getString(R.string.login), getString(R.string.tagFragmentLogin), true, true);
|
||||
}
|
||||
|
||||
loadFragment(fragment, getString(R.string.login), getString(R.string.tagFragmentLogin), true);
|
||||
private void loadSignedInFragment() {
|
||||
Fragment fragment = SignedInFragment.newInstance();
|
||||
loadFragment(fragment, getString(R.string.welcome), getString(R.string.tagFragmentSignedIn), true, true);
|
||||
}
|
||||
|
||||
private void loadSignupFragment() {
|
||||
Fragment fragment = SignupFragment.newInstance();
|
||||
loadFragment(fragment, getString(R.string.signup), getString(R.string.tagFragmentSignup), true, false);
|
||||
}
|
||||
|
||||
private void loadPrivacyPolicyFragment() {
|
||||
Fragment fragment = PolicyFragment.newInstance();
|
||||
|
||||
loadFragment(fragment, getString(R.string.privacyPolicy), getString(R.string.tagFragmentPolicy), true);
|
||||
loadFragment(fragment, getString(R.string.privacyPolicy), getString(R.string.tagFragmentPolicy), true, true);
|
||||
}
|
||||
|
||||
private void loadPeopleFragment() {
|
||||
Fragment fragment = FriendsFragment.newInstance();
|
||||
|
||||
loadFragment(fragment, getString(R.string.people), getString(R.string.tagFragmentPeople), true);
|
||||
loadFragment(fragment, getString(R.string.people), getString(R.string.tagFragmentPeople), true, true);
|
||||
}
|
||||
|
||||
private void loadFragment(Fragment fragment, String title, String tag, boolean addToBackStack) {
|
||||
private void loadSettingsFragment() {
|
||||
SettingsFragment fragment = SettingsFragment.newInstance();
|
||||
|
||||
loadFragment(fragment, getString(R.string.settings), getString(R.string.tagSettings), true, true);
|
||||
}
|
||||
|
||||
|
||||
private void loadFragment(Fragment newFragment, String title, String tag, boolean addToBackStack, boolean goBackUntilHome) {
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
|
||||
// check if it's the same fragment
|
||||
@ -163,17 +199,19 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
return; // cancel as we are already in that fragment
|
||||
}
|
||||
|
||||
// go back until first transaction
|
||||
int backStackEntryCount = fragmentManager.getBackStackEntryCount();
|
||||
for (int i = 0; i < backStackEntryCount - 1; i++) {
|
||||
fragmentManager.popBackStackImmediate();
|
||||
if (goBackUntilHome) {
|
||||
// go back until first transaction
|
||||
int backStackEntryCount = fragmentManager.getBackStackEntryCount();
|
||||
for (int i = 0; i < backStackEntryCount - 1; i++) {
|
||||
fragmentManager.popBackStackImmediate();
|
||||
}
|
||||
}
|
||||
|
||||
// this case is when we wanted to go home.. rollback already did that!
|
||||
// But asking for a new Home fragment makes it easier to have an updated list so we let it to continue
|
||||
|
||||
FragmentTransaction ft = fragmentManager.beginTransaction();
|
||||
ft.replace(R.id.content_frame, fragment, tag);
|
||||
ft.replace(R.id.content_frame, newFragment, tag);
|
||||
|
||||
if (addToBackStack) {
|
||||
ft.addToBackStack(title);
|
||||
@ -241,6 +279,9 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
case R.id.action_people:
|
||||
loadPeopleFragment();
|
||||
return true;
|
||||
case R.id.action_debug_settings:
|
||||
loadSettingsFragment();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -278,7 +319,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
}
|
||||
|
||||
private void goToLastLocation() {
|
||||
goToDomain("");
|
||||
goToDomain(backToUrl != null? backToUrl : "");
|
||||
}
|
||||
|
||||
private void goToDomain(String domainUrl) {
|
||||
@ -307,6 +348,32 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGettingStarted() {
|
||||
loadHomeFragment(false);
|
||||
if (backToScene) {
|
||||
backToScene = false;
|
||||
goToLastLocation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoginRequested() {
|
||||
// go back from signup to login
|
||||
onBackPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSignupRequested() {
|
||||
loadSignupFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSignupCompleted() {
|
||||
loadSignedInFragment();
|
||||
updateLoginMenu();
|
||||
}
|
||||
|
||||
public void handleUsernameChanged(String username) {
|
||||
runOnUiThread(() -> updateProfileHeader(username));
|
||||
}
|
||||
|
@ -4,12 +4,10 @@ import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -19,19 +17,26 @@ import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.qtproject.qt5.android.QtNative;
|
||||
|
||||
import io.highfidelity.hifiinterface.R;
|
||||
|
||||
import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationActive;
|
||||
import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationInactive;
|
||||
|
||||
public class LoginFragment extends Fragment {
|
||||
|
||||
private EditText mUsername;
|
||||
private EditText mPassword;
|
||||
private TextView mError;
|
||||
private TextView mForgotPassword;
|
||||
private TextView mSignup;
|
||||
private Button mLoginButton;
|
||||
|
||||
private ProgressDialog mDialog;
|
||||
|
||||
public native void nativeLogin(String username, String password, Activity usernameChangedListener);
|
||||
public native void nativeCancelLogin();
|
||||
|
||||
private LoginFragment.OnLoginInteractionListener mListener;
|
||||
|
||||
@ -54,48 +59,12 @@ public class LoginFragment extends Fragment {
|
||||
mError = rootView.findViewById(R.id.error);
|
||||
mLoginButton = rootView.findViewById(R.id.loginButton);
|
||||
mForgotPassword = rootView.findViewById(R.id.forgotPassword);
|
||||
|
||||
mUsername.addTextChangedListener(new TextWatcher() {
|
||||
boolean ignoreNextChange = false;
|
||||
boolean hadBlankSpace = false;
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) {
|
||||
hadBlankSpace = charSequence.length() > 0 && charSequence.charAt(charSequence.length()-1) == ' ';
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence charSequence, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
if (!ignoreNextChange) {
|
||||
ignoreNextChange = true;
|
||||
boolean spaceFound = false;
|
||||
for (int i = 0; i < editable.length(); i++) {
|
||||
if (editable.charAt(i) == ' ') {
|
||||
spaceFound=true;
|
||||
editable.delete(i, i + 1);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
if (hadBlankSpace && !spaceFound && editable.length() > 0) {
|
||||
editable.delete(editable.length()-1, editable.length());
|
||||
}
|
||||
|
||||
editable.append(' ');
|
||||
ignoreNextChange = false;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
mSignup = rootView.findViewById(R.id.signupButton);
|
||||
|
||||
mLoginButton.setOnClickListener(view -> login());
|
||||
|
||||
mForgotPassword.setOnClickListener(view -> forgotPassword());
|
||||
mSignup.setOnClickListener(view -> signup());
|
||||
|
||||
mPassword.setOnEditorActionListener(
|
||||
(textView, actionId, keyEvent) -> {
|
||||
@ -125,10 +94,19 @@ public class LoginFragment extends Fragment {
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// This hack intends to keep Qt threads running even after the app comes from background
|
||||
QtNative.setApplicationState(ApplicationActive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
cancelActivityIndicator();
|
||||
// Leave the Qt app paused
|
||||
QtNative.setApplicationState(ApplicationInactive);
|
||||
hideKeyboard();
|
||||
}
|
||||
|
||||
@ -146,6 +124,12 @@ public class LoginFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
|
||||
public void signup() {
|
||||
if (mListener != null) {
|
||||
mListener.onSignupRequested();
|
||||
}
|
||||
}
|
||||
|
||||
private void hideKeyboard() {
|
||||
View view = getActivity().getCurrentFocus();
|
||||
if (view != null) {
|
||||
@ -164,7 +148,15 @@ public class LoginFragment extends Fragment {
|
||||
mDialog = new ProgressDialog(getContext());
|
||||
}
|
||||
mDialog.setMessage(getString(R.string.logging_in));
|
||||
mDialog.setCancelable(false);
|
||||
mDialog.setCancelable(true);
|
||||
mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialogInterface) {
|
||||
nativeCancelLogin();
|
||||
cancelActivityIndicator();
|
||||
mLoginButton.setEnabled(true);
|
||||
}
|
||||
});
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
@ -184,7 +176,6 @@ public class LoginFragment extends Fragment {
|
||||
}
|
||||
|
||||
public void handleLoginCompleted(boolean success) {
|
||||
Log.d("[LOGIN]", "handleLoginCompleted " + success);
|
||||
getActivity().runOnUiThread(() -> {
|
||||
mLoginButton.setEnabled(true);
|
||||
cancelActivityIndicator();
|
||||
@ -200,6 +191,7 @@ public class LoginFragment extends Fragment {
|
||||
|
||||
public interface OnLoginInteractionListener {
|
||||
void onLoginCompleted();
|
||||
void onSignupRequested();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
package io.highfidelity.hifiinterface.fragment;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.media.audiofx.AcousticEchoCanceler;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import io.highfidelity.hifiinterface.R;
|
||||
|
||||
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
public native void updateHifiSetting(String group, String key, boolean value);
|
||||
public native boolean getHifiSettingBoolean(String group, String key, boolean defaultValue);
|
||||
|
||||
private final String HIFI_SETTINGS_ANDROID_GROUP = "Android";
|
||||
private final String HIFI_SETTINGS_AEC_KEY = "aec";
|
||||
private final String PREFERENCE_KEY_AEC = "aec";
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.settings);
|
||||
|
||||
if (!AcousticEchoCanceler.isAvailable()) {
|
||||
getPreferenceScreen().getPreferenceManager().findPreference("aec").setEnabled(false);
|
||||
}
|
||||
|
||||
getPreferenceScreen().getSharedPreferences().edit().putBoolean(PREFERENCE_KEY_AEC,
|
||||
getHifiSettingBoolean(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, false));
|
||||
}
|
||||
|
||||
public static SettingsFragment newInstance() {
|
||||
SettingsFragment fragment = new SettingsFragment();
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
Preference pref = findPreference(key);
|
||||
switch (key) {
|
||||
case "aec":
|
||||
updateHifiSetting(HIFI_SETTINGS_ANDROID_GROUP, HIFI_SETTINGS_AEC_KEY, sharedPreferences.getBoolean(key, false));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package io.highfidelity.hifiinterface.fragment;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.Html;
|
||||
import android.text.Spanned;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import io.highfidelity.hifiinterface.R;
|
||||
|
||||
public class SignedInFragment extends Fragment {
|
||||
|
||||
private Button mGetStartedButton;
|
||||
private OnSignedInInteractionListener mListener;
|
||||
|
||||
public SignedInFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
||||
public static SignedInFragment newInstance() {
|
||||
SignedInFragment fragment = new SignedInFragment();
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_signedin, container, false);
|
||||
mGetStartedButton = rootView.findViewById(R.id.getStarted);
|
||||
|
||||
mGetStartedButton.setOnClickListener(view -> {
|
||||
getStarted();
|
||||
});
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof SignedInFragment.OnSignedInInteractionListener) {
|
||||
mListener = (SignedInFragment.OnSignedInInteractionListener) context;
|
||||
} else {
|
||||
throw new RuntimeException(context.toString()
|
||||
+ " must implement OnSignedInInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
public void getStarted() {
|
||||
if (mListener != null) {
|
||||
mListener.onGettingStarted();
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnSignedInInteractionListener {
|
||||
void onGettingStarted();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
package io.highfidelity.hifiinterface.fragment;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.qtproject.qt5.android.QtNative;
|
||||
|
||||
import io.highfidelity.hifiinterface.R;
|
||||
|
||||
import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationActive;
|
||||
import static org.qtproject.qt5.android.QtActivityDelegate.ApplicationInactive;
|
||||
|
||||
public class SignupFragment extends Fragment {
|
||||
|
||||
private EditText mEmail;
|
||||
private EditText mUsername;
|
||||
private EditText mPassword;
|
||||
private TextView mError;
|
||||
private TextView mCancelButton;
|
||||
|
||||
private Button mSignupButton;
|
||||
|
||||
private ProgressDialog mDialog;
|
||||
|
||||
public native void nativeSignup(String email, String username, String password); // move to SignupFragment
|
||||
public native void nativeCancelSignup();
|
||||
public native void nativeLogin(String username, String password, Activity usernameChangedListener);
|
||||
public native void nativeCancelLogin();
|
||||
|
||||
private SignupFragment.OnSignupInteractionListener mListener;
|
||||
|
||||
public SignupFragment() {
|
||||
// Required empty public constructor
|
||||
}
|
||||
|
||||
public static SignupFragment newInstance() {
|
||||
SignupFragment fragment = new SignupFragment();
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_signup, container, false);
|
||||
|
||||
mEmail = rootView.findViewById(R.id.email);
|
||||
mUsername = rootView.findViewById(R.id.username);
|
||||
mPassword = rootView.findViewById(R.id.password);
|
||||
mError = rootView.findViewById(R.id.error);
|
||||
mSignupButton = rootView.findViewById(R.id.signupButton);
|
||||
mCancelButton = rootView.findViewById(R.id.cancelButton);
|
||||
|
||||
mSignupButton.setOnClickListener(view -> signup());
|
||||
mCancelButton.setOnClickListener(view -> login());
|
||||
mPassword.setOnEditorActionListener(
|
||||
(textView, actionId, keyEvent) -> {
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
mSignupButton.performClick();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Context context) {
|
||||
super.onAttach(context);
|
||||
if (context instanceof OnSignupInteractionListener) {
|
||||
mListener = (OnSignupInteractionListener) context;
|
||||
} else {
|
||||
throw new RuntimeException(context.toString()
|
||||
+ " must implement OnSignupInteractionListener");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
mListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
// This hack intends to keep Qt threads running even after the app comes from background
|
||||
QtNative.setApplicationState(ApplicationActive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
cancelActivityIndicator();
|
||||
// Leave the Qt app paused
|
||||
QtNative.setApplicationState(ApplicationInactive);
|
||||
hideKeyboard();
|
||||
}
|
||||
|
||||
private void login() {
|
||||
if (mListener != null) {
|
||||
mListener.onLoginRequested();
|
||||
}
|
||||
}
|
||||
|
||||
public void signup() {
|
||||
String email = mEmail.getText().toString().trim();
|
||||
String username = mUsername.getText().toString().trim();
|
||||
String password = mPassword.getText().toString();
|
||||
hideKeyboard();
|
||||
if (email.isEmpty() || username.isEmpty() || password.isEmpty()) {
|
||||
showError(getString(R.string.signup_email_username_or_password_incorrect));
|
||||
} else {
|
||||
mSignupButton.setEnabled(false);
|
||||
hideError();
|
||||
showActivityIndicator();
|
||||
nativeSignup(email, username, password);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideKeyboard() {
|
||||
View view = getActivity().getCurrentFocus();
|
||||
if (view != null) {
|
||||
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void showActivityIndicator() {
|
||||
if (mDialog == null) {
|
||||
mDialog = new ProgressDialog(getContext());
|
||||
}
|
||||
mDialog.setMessage(getString(R.string.creating_account));
|
||||
mDialog.setCancelable(true);
|
||||
mDialog.setOnCancelListener(dialogInterface -> {
|
||||
nativeCancelSignup();
|
||||
cancelActivityIndicator();
|
||||
mSignupButton.setEnabled(true);
|
||||
});
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
private void cancelActivityIndicator() {
|
||||
if (mDialog != null) {
|
||||
mDialog.cancel();
|
||||
}
|
||||
}
|
||||
private void showError(String error) {
|
||||
mError.setText(error);
|
||||
mError.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
private void hideError() {
|
||||
mError.setText("");
|
||||
mError.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
public interface OnSignupInteractionListener {
|
||||
void onSignupCompleted();
|
||||
void onLoginRequested();
|
||||
}
|
||||
|
||||
public void handleSignupCompleted() {
|
||||
String username = mUsername.getText().toString().trim();
|
||||
String password = mPassword.getText().toString();
|
||||
mDialog.setMessage(getString(R.string.logging_in));
|
||||
mDialog.setCancelable(true);
|
||||
mDialog.setOnCancelListener(dialogInterface -> {
|
||||
nativeCancelLogin();
|
||||
cancelActivityIndicator();
|
||||
if (mListener != null) {
|
||||
mListener.onLoginRequested();
|
||||
}
|
||||
});
|
||||
mDialog.show();
|
||||
nativeLogin(username, password, getActivity());
|
||||
}
|
||||
|
||||
public void handleSignupFailed(String error) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
mSignupButton.setEnabled(true);
|
||||
cancelActivityIndicator();
|
||||
mError.setText(error);
|
||||
mError.setVisibility(View.VISIBLE);
|
||||
});
|
||||
}
|
||||
|
||||
public void handleLoginCompleted(boolean success) {
|
||||
getActivity().runOnUiThread(() -> {
|
||||
mSignupButton.setEnabled(true);
|
||||
cancelActivityIndicator();
|
||||
|
||||
if (success) {
|
||||
if (mListener != null) {
|
||||
mListener.onSignupCompleted();
|
||||
}
|
||||
} else {
|
||||
// Registration was successful but login failed.
|
||||
// Let the user to login manually
|
||||
mListener.onLoginRequested();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package io.highfidelity.hifiinterface.receiver;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioManager;
|
||||
import android.util.Log;
|
||||
|
||||
public class HeadsetStateReceiver extends BroadcastReceiver {
|
||||
|
||||
private native void notifyHeadsetOn(boolean pluggedIn);
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
notifyHeadsetOn(audioManager.isWiredHeadsetOn());
|
||||
}
|
||||
}
|
27
android/app/src/main/res/drawable/ic_eye_noshow.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="36dp"
|
||||
android:height="22dp"
|
||||
android:viewportWidth="36"
|
||||
android:viewportHeight="22">
|
||||
|
||||
<path
|
||||
android:fillColor="#3D3D3D"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M3.59534,11.0156 C6.16042,13.4128,9.65987,15.5898,13.6042,16.1774 C17.686,16.7856,22.4164,15.7196,27.3057,11.0659 C22.0721,6.07309,17.0642,5.14115,12.9153,5.90073 C8.99427,6.61859,5.69298,8.87688,3.59534,11.0156 Z M12.455,3.27591 C17.7727,2.30235,23.9836,3.74895,30.1053,10.1333 L31,11.0664 L30.1053,11.9994 C24.3636,17.9875,18.4774,19.5983,13.2276,18.8161 C8.06048,18.0463,3.70384,14.9892,0.837069,11.9994 L0,11.1265 L0.778477,10.1986 C3.05338,7.48717,7.2318,4.23217,12.455,3.27591 Z" />
|
||||
<path
|
||||
android:fillColor="#3D3D3D"
|
||||
android:pathData="M15.6539,7.11119 C17.6719,7.11119,19.3078,8.81726,19.3078,10.9218 C19.3078,13.0263,17.6719,14.7324,15.6539,14.7324 C13.6359,14.7324,12,13.0263,12,10.9218 C12,8.81726,13.6359,7.11119,15.6539,7.11119 Z" />
|
||||
<!--path
|
||||
android:fillColor="#000000"
|
||||
android:strokeColor="#ffffff"
|
||||
android:strokeWidth="2.7"
|
||||
android:strokeLineCap="round"
|
||||
android:pathData="M27,2.90919 L8.90919,21" /-->
|
||||
<path
|
||||
android:fillColor="#000000"
|
||||
android:strokeColor="#3D3D3D"
|
||||
android:strokeWidth="3"
|
||||
android:strokeLineCap="round"
|
||||
android:pathData="M25,2.12132 L7.12132,20" />
|
||||
</vector>
|
15
android/app/src/main/res/drawable/ic_eye_show.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="36dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="36"
|
||||
android:viewportHeight="16">
|
||||
|
||||
<path
|
||||
android:fillColor="#3D3D3D"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M3.59534,8.01564 C6.16042,10.4128,9.65987,12.5898,13.6042,13.1774 C17.686,13.7856,22.4164,12.7196,27.3057,8.06585 C22.0721,3.07309,17.0642,2.14115,12.9153,2.90073 C8.99427,3.61859,5.69298,5.87688,3.59534,8.01564 Z M12.455,0.275915 C17.7727,-0.697651,23.9836,0.748949,30.1053,7.13329 L31,8.06636 L30.1053,8.99944 C24.3636,14.9875,18.4774,16.5983,13.2276,15.8161 C8.06048,15.0463,3.70384,11.9892,0.837069,8.99944 L0,8.12646 L0.778477,7.1986 C3.05338,4.48717,7.2318,1.23217,12.455,0.275915 Z" />
|
||||
<path
|
||||
android:fillColor="#3D3D3D"
|
||||
android:pathData="M15.6441,4.11118 C17.6621,4.11118,19.298,5.81725,19.298,7.92179 C19.298,10.0263,17.6621,11.7324,15.6441,11.7324 C13.6261,11.7324,11.9902,10.0263,11.9902,7.92179 C11.9902,5.81725,13.6261,4.11118,15.6441,4.11118 Z" />
|
||||
</vector>
|
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<item android:state_pressed="true" >
|
||||
<shape android:shape="rectangle" >
|
||||
<corners android:radius="4dip" />
|
||||
<stroke android:width="1dip" android:color="@color/colorButton2" />
|
||||
<solid android:color="@color/colorButton2"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:state_focused="true">
|
||||
<shape android:shape="rectangle" >
|
||||
<corners android:radius="4dip" />
|
||||
<stroke android:width="1dip" android:color="@color/colorButton2" />
|
||||
<solid android:color="@color/colorButton2"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="rectangle" >
|
||||
<corners android:radius="4dip" />
|
||||
<stroke android:width="1dip" android:color="@color/colorButton2" />
|
||||
<solid android:color="@color/colorButton2"/>
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_checked="true" android:drawable="@drawable/ic_eye_noshow"/>
|
||||
<item android:drawable="@drawable/ic_eye_show" />
|
||||
</selector>
|
@ -21,10 +21,12 @@
|
||||
android:id="@+id/error"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginBottom="25dp"
|
||||
android:layout_marginLeft="9dp"
|
||||
android:layout_marginRight="9dp"
|
||||
android:fontFamily="@font/raleway"
|
||||
android:textColor="@color/colorLoginError"
|
||||
android:textSize="12sp"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toTopOf="@id/username"
|
||||
app:layout_constraintLeft_toLeftOf="@id/username"
|
||||
android:visibility="invisible"/>
|
||||
@ -41,72 +43,100 @@
|
||||
android:paddingTop="14dp"
|
||||
android:ems="10"
|
||||
android:fontFamily="@font/raleway"
|
||||
android:textSize="14sp"
|
||||
android:textSize="17sp"
|
||||
android:inputType="textEmailAddress"
|
||||
android:textStyle="italic"
|
||||
android:textColor="@color/editTextColor"
|
||||
android:textColorHint="@color/editTextColor"
|
||||
android:gravity="right|center_vertical"
|
||||
android:gravity="left|center_vertical"
|
||||
app:layout_constraintTop_toBottomOf="@id/header"
|
||||
android:layout_marginTop="70dp"
|
||||
android:hint="@string/username_or_email" />
|
||||
|
||||
<EditText
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/passwordLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="46dp"
|
||||
android:layout_marginRight="46dp"
|
||||
app:passwordToggleTint="@color/showPasswordColor"
|
||||
app:passwordToggleEnabled="true"
|
||||
app:hintAnimationEnabled="false"
|
||||
app:passwordToggleDrawable="@drawable/selector_show_password"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintTop_toBottomOf="@id/username"
|
||||
android:layout_marginTop="13dp"
|
||||
>
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
android:layout_marginLeft="46dp"
|
||||
android:layout_marginRight="46dp"
|
||||
android:background="@drawable/rounded_edit"
|
||||
android:padding="7dp"
|
||||
android:paddingRight="12dp"
|
||||
android:drawablePadding="55dp"
|
||||
android:paddingTop="14dp"
|
||||
android:drawableEnd="@drawable/ic_eye_noshow"
|
||||
android:ems="10"
|
||||
android:fontFamily="@font/raleway"
|
||||
android:textSize="14sp"
|
||||
android:inputType="textPassword"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="italic"
|
||||
android:textColor="@color/editTextColor"
|
||||
android:textColorHint="@color/editTextColor"
|
||||
android:gravity="right|center_vertical"
|
||||
app:layout_constraintTop_toBottomOf="@id/username"
|
||||
android:gravity="left|center_vertical"
|
||||
android:imeOptions="actionDone"
|
||||
android:hint="@string/password"
|
||||
android:layout_marginTop="13dp"
|
||||
android:imeOptions="actionDone"/>
|
||||
android:inputType="textPassword" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/loginButton"
|
||||
android:layout_width="154dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:fontFamily="@font/raleway_semibold"
|
||||
android:paddingBottom="0dp"
|
||||
android:paddingLeft="55dp"
|
||||
android:paddingRight="55dp"
|
||||
android:paddingTop="0dp"
|
||||
android:text="@string/login"
|
||||
android:textColor="@color/white_opaque"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="15sp"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintRight_toRightOf="@id/username"
|
||||
app:layout_constraintTop_toBottomOf="@id/password"
|
||||
app:layout_constraintTop_toBottomOf="@id/forgotPassword"
|
||||
app:layout_goneMarginTop="4dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/forgotPassword"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="9dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:fontFamily="@font/raleway_semibold"
|
||||
android:textSize="14dp"
|
||||
android:text="@string/forgot_password"
|
||||
android:textStyle="italic"
|
||||
android:paddingRight="10dp"
|
||||
app:layout_constraintLeft_toLeftOf="@id/password"
|
||||
app:layout_constraintTop_toTopOf="@id/loginButton"
|
||||
app:layout_constraintRight_toLeftOf="@id/loginButton"
|
||||
app:layout_constraintRight_toRightOf="@id/passwordLayout"
|
||||
app:layout_constraintTop_toBottomOf="@id/passwordLayout"
|
||||
android:textColor="@color/colorButton1"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/signupButton"
|
||||
android:layout_width="0dp"
|
||||
app:layout_constraintWidth_default="spread"
|
||||
android:layout_height="38dp"
|
||||
android:background="@drawable/rounded_secondary_button"
|
||||
android:fontFamily="@font/raleway_semibold"
|
||||
android:paddingBottom="0dp"
|
||||
android:paddingTop="0dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:text="@string/signup"
|
||||
android:textColor="@color/white_opaque"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintLeft_toLeftOf="@id/passwordLayout"
|
||||
app:layout_constraintTop_toTopOf="@id/loginButton"
|
||||
app:layout_constraintRight_toLeftOf="@id/loginButton"
|
||||
app:layout_goneMarginTop="4dp"/>
|
||||
|
||||
|
||||
|
||||
|
63
android/app/src/main/res/layout/fragment_signedin.xml
Normal file
@ -0,0 +1,63 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/backgroundLight">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/header"
|
||||
android:layout_width="@dimen/header_hifi_width"
|
||||
android:layout_height="@dimen/header_hifi_height"
|
||||
android:layout_marginTop="@dimen/header_hifi_margin_top"
|
||||
android:contentDescription="HighFidelity"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/hifi_header" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcome"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="50dp"
|
||||
android:paddingLeft="86dp"
|
||||
android:paddingRight="86dp"
|
||||
android:fontFamily="@font/raleway"
|
||||
android:textColor="@color/clearText"
|
||||
android:textSize="24sp"
|
||||
android:text="@string/signedin_welcome"
|
||||
app:layout_constraintTop_toBottomOf="@id/header"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:gravity="center"
|
||||
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/getStarted"
|
||||
android:layout_width="217dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:fontFamily="@font/raleway_semibold"
|
||||
android:paddingBottom="0dp"
|
||||
android:paddingLeft="25dp"
|
||||
android:paddingRight="25dp"
|
||||
android:paddingTop="0dp"
|
||||
android:text="@string/get_started"
|
||||
android:textColor="@color/white_opaque"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintTop_toBottomOf="@id/welcome"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
|
||||
app:layout_goneMarginTop="4dp"/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
151
android/app/src/main/res/layout/fragment_signup.xml
Normal file
@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/backgroundLight">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/header"
|
||||
android:layout_width="@dimen/header_hifi_width"
|
||||
android:layout_height="@dimen/header_hifi_height"
|
||||
android:layout_marginTop="@dimen/header_hifi_margin_top"
|
||||
android:contentDescription="HighFidelity"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/hifi_header" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/error"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginLeft="9dp"
|
||||
android:layout_marginRight="9dp"
|
||||
android:fontFamily="@font/raleway"
|
||||
android:textColor="@color/colorLoginError"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toTopOf="@id/email"
|
||||
app:layout_constraintLeft_toLeftOf="@id/email"
|
||||
app:layout_constraintRight_toRightOf="@id/email"
|
||||
android:visibility="invisible"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
android:layout_marginLeft="46dp"
|
||||
android:layout_marginRight="46dp"
|
||||
android:background="@drawable/rounded_edit"
|
||||
android:padding="7dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingTop="14dp"
|
||||
android:ems="10"
|
||||
android:fontFamily="@font/raleway"
|
||||
android:textSize="17sp"
|
||||
android:inputType="textEmailAddress"
|
||||
android:textStyle="italic"
|
||||
android:textColor="@color/editTextColor"
|
||||
android:textColorHint="@color/editTextColor"
|
||||
android:gravity="left|center_vertical"
|
||||
app:layout_constraintTop_toBottomOf="@id/header"
|
||||
android:layout_marginTop="70dp"
|
||||
android:hint="@string/email" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
android:layout_marginLeft="46dp"
|
||||
android:layout_marginRight="46dp"
|
||||
android:background="@drawable/rounded_edit"
|
||||
android:padding="7dp"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingTop="14dp"
|
||||
android:ems="10"
|
||||
android:fontFamily="@font/raleway"
|
||||
android:textSize="17sp"
|
||||
android:inputType="text"
|
||||
android:textStyle="italic"
|
||||
android:textColor="@color/editTextColor"
|
||||
android:textColorHint="@color/editTextColor"
|
||||
android:gravity="left|center_vertical"
|
||||
app:layout_constraintTop_toBottomOf="@id/email"
|
||||
android:layout_marginTop="7dp"
|
||||
android:hint="@string/username" />
|
||||
|
||||
|
||||
<android.support.design.widget.TextInputLayout
|
||||
android:id="@+id/passwordLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="46dp"
|
||||
android:layout_marginRight="46dp"
|
||||
app:passwordToggleTint="@color/showPasswordColor"
|
||||
app:passwordToggleEnabled="true"
|
||||
app:hintAnimationEnabled="false"
|
||||
app:passwordToggleDrawable="@drawable/selector_show_password"
|
||||
app:hintEnabled="false"
|
||||
app:layout_constraintTop_toBottomOf="@id/username"
|
||||
android:layout_marginTop="7dp"
|
||||
>
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="35dp"
|
||||
android:background="@drawable/rounded_edit"
|
||||
android:padding="7dp"
|
||||
android:drawablePadding="55dp"
|
||||
android:paddingTop="14dp"
|
||||
android:drawableEnd="@drawable/ic_eye_noshow"
|
||||
android:ems="10"
|
||||
android:fontFamily="@font/raleway"
|
||||
android:textSize="17sp"
|
||||
android:textStyle="italic"
|
||||
android:textColor="@color/editTextColor"
|
||||
android:textColorHint="@color/editTextColor"
|
||||
android:gravity="left|center_vertical"
|
||||
android:imeOptions="actionDone"
|
||||
android:hint="@string/password"
|
||||
android:inputType="textPassword" />
|
||||
</android.support.design.widget.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/signupButton"
|
||||
android:layout_width="154dp"
|
||||
android:layout_height="38dp"
|
||||
android:layout_marginTop="44dp"
|
||||
android:background="@drawable/rounded_button"
|
||||
android:fontFamily="@font/raleway_semibold"
|
||||
android:paddingBottom="0dp"
|
||||
android:paddingTop="0dp"
|
||||
android:text="@string/signup"
|
||||
android:textColor="@color/white_opaque"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintRight_toRightOf="@id/username"
|
||||
app:layout_constraintTop_toBottomOf="@id/passwordLayout"
|
||||
app:layout_goneMarginTop="4dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancelButton"
|
||||
android:layout_width="0dp"
|
||||
app:layout_constraintWidth_default="spread"
|
||||
android:layout_height="38dp"
|
||||
android:background="@drawable/rounded_secondary_button"
|
||||
android:fontFamily="@font/raleway_semibold"
|
||||
android:paddingBottom="0dp"
|
||||
android:paddingTop="0dp"
|
||||
android:layout_marginRight="15dp"
|
||||
android:text="@string/cancel"
|
||||
android:textColor="@color/white_opaque"
|
||||
android:textAllCaps="false"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintLeft_toLeftOf="@id/passwordLayout"
|
||||
app:layout_constraintTop_toTopOf="@id/signupButton"
|
||||
app:layout_constraintRight_toLeftOf="@id/signupButton"
|
||||
app:layout_goneMarginTop="4dp"/>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
@ -9,4 +9,9 @@
|
||||
android:id="@+id/action_people"
|
||||
android:title="@string/people"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/action_debug_settings"
|
||||
android:title="@string/settings"
|
||||
android:visible="false"
|
||||
/>
|
||||
</menu>
|
||||
|
@ -6,8 +6,10 @@
|
||||
<color name="colorAccent">#54D7FD</color>
|
||||
<color name="backgroundEditText">#E3E3E3</color>
|
||||
<color name="editTextColor">#575757</color>
|
||||
<color name="showPasswordColor">#3D3D3D</color>
|
||||
<color name="tabs">#1EB5EC</color>
|
||||
<color name="colorButton1">#00B4EF</color>
|
||||
<color name="colorButton2">#828282</color>
|
||||
<color name="backgroundDark">#333333</color>
|
||||
<color name="backgroundLight">#4F4F4F</color>
|
||||
<color name="backgroundSearch">#33999999</color>
|
||||
@ -22,4 +24,6 @@
|
||||
<color name="starSelectedTint">#FBD92A</color>
|
||||
<color name="starUnselectedTint">#8A8A8A</color>
|
||||
<color name="slidingUpPanelFadeColor">#40000000</color>
|
||||
<color name="clearText">#F2F2F2</color>
|
||||
|
||||
</resources>
|
||||
|
@ -10,11 +10,13 @@
|
||||
<string name="popular">POPULAR</string>
|
||||
<string name="bookmarks">BOOKMARKS</string>
|
||||
<string name="goto_url_hint">Type a domain url</string>
|
||||
<string name="username_or_email">Username or email\u00A0</string>
|
||||
<string name="password">Password\u00A0</string>
|
||||
<string name="email">Email</string>
|
||||
<string name="username">Username</string>
|
||||
<string name="username_or_email">Username or email</string>
|
||||
<string name="password">Password</string>
|
||||
<string name="login">Login</string>
|
||||
<string name="logout">Logout</string>
|
||||
<string name="forgot_password">Forgot password?\u00A0</string>
|
||||
<string name="forgot_password"><u>Forgot password?</u>\u00A0</string>
|
||||
<string name="login_username_or_password_incorrect">Username or password incorrect.</string>
|
||||
<string name="logging_in">Logging into High Fidelity</string>
|
||||
<string name="search_hint"><i>Search for a place by name</i>\u00A0</string>
|
||||
@ -23,10 +25,24 @@
|
||||
<string name="privacyPolicy">Privacy Policy</string>
|
||||
<string name="your_last_location">Your Last Location</string>
|
||||
<string name="online">Online</string>
|
||||
<string name="signup">Sign Up</string>
|
||||
<string name="creating_account">Creating your High Fidelity account</string>
|
||||
<string name="signup_email_username_or_password_incorrect">Email, username or password incorrect.</string>
|
||||
<string name="signedin_welcome">You are now signed into High Fidelity</string>
|
||||
<string name="welcome">Welcome</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="get_started">Get Started</string>
|
||||
|
||||
<!-- tags -->
|
||||
<string name="tagFragmentHome">tagFragmentHome</string>
|
||||
<string name="tagFragmentLogin">tagFragmentLogin</string>
|
||||
<string name="tagFragmentSignup">tagFragmentSignup</string>
|
||||
<string name="tagFragmentPolicy">tagFragmentPolicy</string>
|
||||
<string name="tagFragmentPeople">tagFragmentPeople</string>
|
||||
<string name="tagSettings">tagSettings</string>
|
||||
<string name="tagFragmentSignedIn">tagFragmentSignedIn</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="AEC">AEC</string>
|
||||
<string name="acoustic_echo_cancellation">Acoustic Echo Cancellation</string>
|
||||
<string name="settings_developer">Developer</string>
|
||||
</resources>
|
||||
|
11
android/app/src/main/res/xml/settings.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory
|
||||
android:title="@string/settings_developer"
|
||||
android:key="pref_key_developer">
|
||||
<SwitchPreference
|
||||
android:key="aec"
|
||||
android:title="@string/AEC"
|
||||
android:summary="@string/acoustic_echo_cancellation" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
@ -72,17 +72,17 @@ def jniFolder = new File(appDir, 'src/main/jniLibs/arm64-v8a')
|
||||
def baseUrl = 'https://hifi-public.s3.amazonaws.com/dependencies/android/'
|
||||
def breakpadDumpSymsDir = new File("${appDir}/build/tmp/breakpadDumpSyms")
|
||||
|
||||
def qtFile='qt-5.11.1_linux_armv8-libcpp_openssl.tgz'
|
||||
def qtChecksum='f312c47cd8b8dbca824c32af4eec5e66'
|
||||
def qtVersionId='nyCGcb91S4QbYeJhUkawO5x1lrLdSNB_'
|
||||
def qtFile='qt-5.11.1_linux_armv8-libcpp_openssl_patched.tgz'
|
||||
def qtChecksum='aa449d4bfa963f3bc9a9dfe558ba29df'
|
||||
def qtVersionId='3S97HBM5G5Xw9EfE52sikmgdN3t6C2MN'
|
||||
if (Os.isFamily(Os.FAMILY_MAC)) {
|
||||
qtFile = 'qt-5.11.1_osx_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='a0c8b394aec5b0fcd46714ca3a53278a'
|
||||
qtVersionId='QNa.lwNJaPc0eGuIL.xZ8ebeTuLL7rh8'
|
||||
qtFile = 'qt-5.11.1_osx_armv8-libcpp_openssl_patched.tgz'
|
||||
qtChecksum='c83cc477c08a892e00c71764dca051a0'
|
||||
qtVersionId='OxBD7iKINv1HbyOXmAmDrBb8AF3N.Kup'
|
||||
} else if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||
qtFile = 'qt-5.11.1_win_armv8-libcpp_openssl.tgz'
|
||||
qtChecksum='d80aed4233ce9e222aae8376e7a94bf9'
|
||||
qtVersionId='iDVXu0i3WEXRFIxQCtzcJ2XuKrE8RIqB'
|
||||
qtFile = 'qt-5.11.1_win_armv8-libcpp_openssl_patched.tgz'
|
||||
qtChecksum='0582191cc55431aa4f660848a542883e'
|
||||
qtVersionId='JfWM0P_Mz5Qp0LwpzhrsRwN3fqlLSFeT'
|
||||
}
|
||||
|
||||
def packages = [
|
||||
|
@ -96,7 +96,6 @@ Agent::Agent(ReceivedMessage& message) :
|
||||
DependencyManager::set<recording::Recorder>();
|
||||
DependencyManager::set<recording::ClipCache>();
|
||||
|
||||
DependencyManager::set<ScriptCache>();
|
||||
DependencyManager::set<RecordingScriptingInterface>();
|
||||
DependencyManager::set<UsersScriptingInterface>();
|
||||
|
||||
@ -177,6 +176,8 @@ void Agent::run() {
|
||||
// Create ScriptEngines on threaded-assignment thread then move to main thread.
|
||||
DependencyManager::set<ScriptEngines>(ScriptEngine::AGENT_SCRIPT)->moveToThread(qApp->thread());
|
||||
|
||||
DependencyManager::set<ScriptCache>();
|
||||
|
||||
// make sure we request our script once the agent connects to the domain
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
@ -360,154 +361,178 @@ void Agent::scriptRequestFinished() {
|
||||
}
|
||||
|
||||
void Agent::executeScript() {
|
||||
_scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload);
|
||||
// the following block is scoped so that any shared pointers we take here
|
||||
// are cleared before we call setFinished at the end of the function
|
||||
{
|
||||
_scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload);
|
||||
|
||||
// setup an Avatar for the script to use
|
||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||
// setup an Avatar for the script to use
|
||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||
|
||||
scriptedAvatar->setID(getSessionUUID());
|
||||
scriptedAvatar->setID(getSessionUUID());
|
||||
|
||||
connect(_scriptEngine.data(), SIGNAL(update(float)),
|
||||
scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection);
|
||||
scriptedAvatar->setForceFaceTrackerConnected(true);
|
||||
connect(_scriptEngine.data(), SIGNAL(update(float)),
|
||||
scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection);
|
||||
scriptedAvatar->setForceFaceTrackerConnected(true);
|
||||
|
||||
// call model URL setters with empty URLs so our avatar, if user, will have the default models
|
||||
scriptedAvatar->setSkeletonModelURL(QUrl());
|
||||
// call model URL setters with empty URLs so our avatar, if user, will have the default models
|
||||
scriptedAvatar->setSkeletonModelURL(QUrl());
|
||||
|
||||
// force lazy initialization of the head data for the scripted avatar
|
||||
// since it is referenced below by computeLoudness and getAudioLoudness
|
||||
scriptedAvatar->getHeadOrientation();
|
||||
// force lazy initialization of the head data for the scripted avatar
|
||||
// since it is referenced below by computeLoudness and getAudioLoudness
|
||||
scriptedAvatar->getHeadOrientation();
|
||||
|
||||
// give this AvatarData object to the script engine
|
||||
_scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data());
|
||||
// give this AvatarData object to the script engine
|
||||
_scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data());
|
||||
|
||||
// give scripts access to the Users object
|
||||
_scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
// give scripts access to the Users object
|
||||
_scriptEngine->registerGlobalObject("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
|
||||
auto player = DependencyManager::get<recording::Deck>();
|
||||
connect(player.data(), &recording::Deck::playbackStateChanged, [=] {
|
||||
if (player->isPlaying()) {
|
||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||
if (recordingInterface->getPlayFromCurrentLocation()) {
|
||||
scriptedAvatar->setRecordingBasis();
|
||||
auto player = DependencyManager::get<recording::Deck>();
|
||||
connect(player.data(), &recording::Deck::playbackStateChanged, [&player, &scriptedAvatar] {
|
||||
if (player->isPlaying()) {
|
||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||
if (recordingInterface->getPlayFromCurrentLocation()) {
|
||||
scriptedAvatar->setRecordingBasis();
|
||||
}
|
||||
|
||||
// these procedural movements are included in the recordings
|
||||
scriptedAvatar->setHasProceduralEyeFaceMovement(false);
|
||||
scriptedAvatar->setHasProceduralBlinkFaceMovement(false);
|
||||
scriptedAvatar->setHasAudioEnabledFaceMovement(false);
|
||||
} else {
|
||||
scriptedAvatar->clearRecordingBasis();
|
||||
|
||||
// restore procedural blendshape movement
|
||||
scriptedAvatar->setHasProceduralEyeFaceMovement(true);
|
||||
scriptedAvatar->setHasProceduralBlinkFaceMovement(true);
|
||||
scriptedAvatar->setHasAudioEnabledFaceMovement(true);
|
||||
}
|
||||
} else {
|
||||
scriptedAvatar->clearRecordingBasis();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
using namespace recording;
|
||||
static const FrameType AVATAR_FRAME_TYPE = Frame::registerFrameType(AvatarData::FRAME_NAME);
|
||||
Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [scriptedAvatar](Frame::ConstPointer frame) {
|
||||
using namespace recording;
|
||||
static const FrameType AVATAR_FRAME_TYPE = Frame::registerFrameType(AvatarData::FRAME_NAME);
|
||||
Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [scriptedAvatar](Frame::ConstPointer frame) {
|
||||
|
||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||
bool useFrameSkeleton = recordingInterface->getPlayerUseSkeletonModel();
|
||||
|
||||
// FIXME - the ability to switch the avatar URL is not actually supported when playing back from a recording
|
||||
if (!useFrameSkeleton) {
|
||||
static std::once_flag warning;
|
||||
std::call_once(warning, [] {
|
||||
qWarning() << "Recording.setPlayerUseSkeletonModel(false) is not currently supported.";
|
||||
});
|
||||
}
|
||||
|
||||
AvatarData::fromFrame(frame->data, *scriptedAvatar);
|
||||
});
|
||||
|
||||
using namespace recording;
|
||||
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName());
|
||||
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) {
|
||||
static quint16 audioSequenceNumber{ 0 };
|
||||
|
||||
QByteArray audio(frame->data);
|
||||
|
||||
if (_isNoiseGateEnabled) {
|
||||
int16_t* samples = reinterpret_cast<int16_t*>(audio.data());
|
||||
int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
|
||||
_audioGate.render(samples, samples, numSamples);
|
||||
}
|
||||
|
||||
computeLoudness(&audio, scriptedAvatar);
|
||||
|
||||
// state machine to detect gate opening and closing
|
||||
bool audioGateOpen = (scriptedAvatar->getAudioLoudness() != 0.0f);
|
||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
||||
_audioGateOpen = audioGateOpen;
|
||||
Q_UNUSED(openedInLastBlock);
|
||||
|
||||
// the codec must be flushed to silence before sending silent packets,
|
||||
// so delay the transition to silent packets by one packet after becoming silent.
|
||||
auto packetType = PacketType::MicrophoneAudioNoEcho;
|
||||
if (!audioGateOpen && !closedInLastBlock) {
|
||||
packetType = PacketType::SilentAudioFrame;
|
||||
}
|
||||
|
||||
Transform audioTransform;
|
||||
auto headOrientation = scriptedAvatar->getHeadOrientation();
|
||||
audioTransform.setTranslation(scriptedAvatar->getWorldPosition());
|
||||
audioTransform.setRotation(headOrientation);
|
||||
|
||||
QByteArray encodedBuffer;
|
||||
if (_encoder) {
|
||||
_encoder->encode(audio, encodedBuffer);
|
||||
} else {
|
||||
encodedBuffer = audio;
|
||||
}
|
||||
|
||||
AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber, false,
|
||||
audioTransform, scriptedAvatar->getWorldPosition(), glm::vec3(0),
|
||||
packetType, _selectedCodecName);
|
||||
});
|
||||
|
||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||
_scriptEngine->registerGlobalObject("AvatarList", avatarHashMap.data());
|
||||
|
||||
// register ourselves to the script engine
|
||||
_scriptEngine->registerGlobalObject("Agent", new AgentScriptingInterface(this));
|
||||
|
||||
_scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCacheScriptingInterface>().data());
|
||||
_scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCacheScriptingInterface>().data());
|
||||
|
||||
QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor);
|
||||
_scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
_scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer);
|
||||
|
||||
_scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||
bool useFrameSkeleton = recordingInterface->getPlayerUseSkeletonModel();
|
||||
_scriptEngine->registerGlobalObject("Recording", recordingInterface.data());
|
||||
|
||||
// FIXME - the ability to switch the avatar URL is not actually supported when playing back from a recording
|
||||
if (!useFrameSkeleton) {
|
||||
static std::once_flag warning;
|
||||
std::call_once(warning, [] {
|
||||
qWarning() << "Recording.setPlayerUseSkeletonModel(false) is not currently supported.";
|
||||
});
|
||||
entityScriptingInterface->init();
|
||||
|
||||
_entityViewer.init();
|
||||
|
||||
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
||||
|
||||
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
||||
|
||||
_avatarAudioTimer.start();
|
||||
|
||||
// Agents should run at 45hz
|
||||
static const int AVATAR_DATA_HZ = 45;
|
||||
static const int AVATAR_DATA_IN_MSECS = MSECS_PER_SECOND / AVATAR_DATA_HZ;
|
||||
QTimer* avatarDataTimer = new QTimer(this);
|
||||
connect(avatarDataTimer, &QTimer::timeout, this, &Agent::processAgentAvatar);
|
||||
avatarDataTimer->setSingleShot(false);
|
||||
avatarDataTimer->setInterval(AVATAR_DATA_IN_MSECS);
|
||||
avatarDataTimer->setTimerType(Qt::PreciseTimer);
|
||||
avatarDataTimer->start();
|
||||
|
||||
_scriptEngine->run();
|
||||
|
||||
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
||||
Frame::clearFrameHandler(AVATAR_FRAME_TYPE);
|
||||
|
||||
if (recordingInterface->isPlaying()) {
|
||||
recordingInterface->stopPlaying();
|
||||
}
|
||||
|
||||
AvatarData::fromFrame(frame->data, *scriptedAvatar);
|
||||
});
|
||||
|
||||
using namespace recording;
|
||||
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName());
|
||||
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) {
|
||||
static quint16 audioSequenceNumber{ 0 };
|
||||
|
||||
QByteArray audio(frame->data);
|
||||
|
||||
if (_isNoiseGateEnabled) {
|
||||
int16_t* samples = reinterpret_cast<int16_t*>(audio.data());
|
||||
int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
|
||||
_audioGate.render(samples, samples, numSamples);
|
||||
if (recordingInterface->isRecording()) {
|
||||
recordingInterface->stopRecording();
|
||||
}
|
||||
|
||||
computeLoudness(&audio, scriptedAvatar);
|
||||
avatarDataTimer->stop();
|
||||
_avatarAudioTimer.stop();
|
||||
}
|
||||
|
||||
// state machine to detect gate opening and closing
|
||||
bool audioGateOpen = (scriptedAvatar->getAudioLoudness() != 0.0f);
|
||||
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
|
||||
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
|
||||
_audioGateOpen = audioGateOpen;
|
||||
Q_UNUSED(openedInLastBlock);
|
||||
|
||||
// the codec must be flushed to silence before sending silent packets,
|
||||
// so delay the transition to silent packets by one packet after becoming silent.
|
||||
auto packetType = PacketType::MicrophoneAudioNoEcho;
|
||||
if (!audioGateOpen && !closedInLastBlock) {
|
||||
packetType = PacketType::SilentAudioFrame;
|
||||
}
|
||||
|
||||
Transform audioTransform;
|
||||
auto headOrientation = scriptedAvatar->getHeadOrientation();
|
||||
audioTransform.setTranslation(scriptedAvatar->getWorldPosition());
|
||||
audioTransform.setRotation(headOrientation);
|
||||
|
||||
QByteArray encodedBuffer;
|
||||
if (_encoder) {
|
||||
_encoder->encode(audio, encodedBuffer);
|
||||
} else {
|
||||
encodedBuffer = audio;
|
||||
}
|
||||
|
||||
AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber, false,
|
||||
audioTransform, scriptedAvatar->getWorldPosition(), glm::vec3(0),
|
||||
packetType, _selectedCodecName);
|
||||
});
|
||||
|
||||
auto avatarHashMap = DependencyManager::set<AvatarHashMap>();
|
||||
_scriptEngine->registerGlobalObject("AvatarList", avatarHashMap.data());
|
||||
|
||||
// register ourselves to the script engine
|
||||
_scriptEngine->registerGlobalObject("Agent", new AgentScriptingInterface(this));
|
||||
|
||||
_scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get<AnimationCacheScriptingInterface>().data());
|
||||
_scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get<SoundCacheScriptingInterface>().data());
|
||||
|
||||
QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor);
|
||||
_scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
|
||||
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
_scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer);
|
||||
|
||||
_scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||
_scriptEngine->registerGlobalObject("Recording", recordingInterface.data());
|
||||
|
||||
entityScriptingInterface->init();
|
||||
|
||||
_entityViewer.init();
|
||||
|
||||
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
|
||||
|
||||
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
|
||||
|
||||
QMetaObject::invokeMethod(&_avatarAudioTimer, "start");
|
||||
|
||||
// Agents should run at 45hz
|
||||
static const int AVATAR_DATA_HZ = 45;
|
||||
static const int AVATAR_DATA_IN_MSECS = MSECS_PER_SECOND / AVATAR_DATA_HZ;
|
||||
QTimer* avatarDataTimer = new QTimer(this);
|
||||
connect(avatarDataTimer, &QTimer::timeout, this, &Agent::processAgentAvatar);
|
||||
avatarDataTimer->setSingleShot(false);
|
||||
avatarDataTimer->setInterval(AVATAR_DATA_IN_MSECS);
|
||||
avatarDataTimer->setTimerType(Qt::PreciseTimer);
|
||||
avatarDataTimer->start();
|
||||
|
||||
_scriptEngine->run();
|
||||
|
||||
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
||||
Frame::clearFrameHandler(AVATAR_FRAME_TYPE);
|
||||
|
||||
DependencyManager::destroy<RecordingScriptingInterface>();
|
||||
setFinished(true);
|
||||
}
|
||||
|
||||
@ -859,17 +884,25 @@ void Agent::aboutToFinish() {
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
DependencyManager::destroy<AudioScriptingInterface>();
|
||||
|
||||
DependencyManager::destroy<RecordingScriptingInterface>();
|
||||
DependencyManager::destroy<recording::Deck>();
|
||||
DependencyManager::destroy<recording::Recorder>();
|
||||
DependencyManager::destroy<recording::ClipCache>();
|
||||
DependencyManager::destroy<ScriptEngine>();
|
||||
|
||||
// drop our shared pointer to the script engine, then ask ScriptEngines to shutdown scripting
|
||||
// this ensures that the ScriptEngine goes down before ScriptEngines
|
||||
_scriptEngine.clear();
|
||||
|
||||
{
|
||||
DependencyManager::get<ScriptEngines>()->shutdownScripting();
|
||||
}
|
||||
|
||||
DependencyManager::destroy<ScriptEngines>();
|
||||
|
||||
DependencyManager::destroy<AssignmentDynamicFactory>();
|
||||
|
||||
DependencyManager::destroy<ScriptableAvatar>();
|
||||
|
||||
QMetaObject::invokeMethod(&_avatarAudioTimer, "stop");
|
||||
|
||||
// cleanup codec & encoder
|
||||
if (_codec && _encoder) {
|
||||
_codec->releaseEncoder(_encoder);
|
||||
|
@ -654,6 +654,15 @@ void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer<ReceivedMessage>
|
||||
|
||||
if (addToIgnore) {
|
||||
senderNode->addIgnoredNode(ignoredUUID);
|
||||
|
||||
if (ignoredNode) {
|
||||
// send a reliable kill packet to remove the sending avatar for the ignored avatar
|
||||
auto killPacket = NLPacket::create(PacketType::KillAvatar,
|
||||
NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true);
|
||||
killPacket->write(senderNode->getUUID().toRfc4122());
|
||||
killPacket->writePrimitive(KillAvatarReason::AvatarDisconnected);
|
||||
nodeList->sendPacket(std::move(killPacket), *ignoredNode);
|
||||
}
|
||||
} else {
|
||||
senderNode->removeIgnoredNode(ignoredUUID);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "AvatarMixerClientData.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <udt/PacketHeaders.h>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
@ -218,6 +219,10 @@ uint16_t AvatarMixerClientData::getLastBroadcastSequenceNumber(const QUuid& node
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointer other) {
|
||||
ignoreOther(self.data(), other.data());
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::ignoreOther(const Node* self, const Node* other) {
|
||||
if (!isRadiusIgnoring(other->getUUID())) {
|
||||
addToRadiusIgnoringSet(other->getUUID());
|
||||
auto killPacket = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true);
|
||||
@ -235,9 +240,20 @@ void AvatarMixerClientData::ignoreOther(SharedNodePointer self, SharedNodePointe
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::removeFromRadiusIgnoringSet(SharedNodePointer self, const QUuid& other) {
|
||||
if (isRadiusIgnoring(other)) {
|
||||
_radiusIgnoredOthers.erase(other);
|
||||
bool AvatarMixerClientData::isRadiusIgnoring(const QUuid& other) const {
|
||||
return std::find(_radiusIgnoredOthers.cbegin(), _radiusIgnoredOthers.cend(), other) != _radiusIgnoredOthers.cend();
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::addToRadiusIgnoringSet(const QUuid& other) {
|
||||
if (!isRadiusIgnoring(other)) {
|
||||
_radiusIgnoredOthers.push_back(other);
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarMixerClientData::removeFromRadiusIgnoringSet(const QUuid& other) {
|
||||
auto ignoredOtherIter = std::find(_radiusIgnoredOthers.cbegin(), _radiusIgnoredOthers.cend(), other);
|
||||
if (ignoredOtherIter != _radiusIgnoredOthers.cend()) {
|
||||
_radiusIgnoredOthers.erase(ignoredOtherIter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
|
||||
#include <QtCore/QJsonObject>
|
||||
@ -45,6 +45,7 @@ public:
|
||||
|
||||
int parseData(ReceivedMessage& message) override;
|
||||
AvatarData& getAvatar() { return *_avatar; }
|
||||
const AvatarData& getAvatar() const { return *_avatar; }
|
||||
const AvatarData* getConstAvatarData() const { return _avatar.get(); }
|
||||
AvatarSharedPointer getAvatarSharedPointer() const { return _avatar; }
|
||||
|
||||
@ -90,11 +91,11 @@ public:
|
||||
void loadJSONStats(QJsonObject& jsonObject) const;
|
||||
|
||||
glm::vec3 getPosition() const { return _avatar ? _avatar->getWorldPosition() : glm::vec3(0); }
|
||||
glm::vec3 getGlobalBoundingBoxCorner() const { return _avatar ? _avatar->getGlobalBoundingBoxCorner() : glm::vec3(0); }
|
||||
bool isRadiusIgnoring(const QUuid& other) const { return _radiusIgnoredOthers.find(other) != _radiusIgnoredOthers.end(); }
|
||||
void addToRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.insert(other); }
|
||||
void removeFromRadiusIgnoringSet(SharedNodePointer self, const QUuid& other);
|
||||
bool isRadiusIgnoring(const QUuid& other) const;
|
||||
void addToRadiusIgnoringSet(const QUuid& other);
|
||||
void removeFromRadiusIgnoringSet(const QUuid& other);
|
||||
void ignoreOther(SharedNodePointer self, SharedNodePointer other);
|
||||
void ignoreOther(const Node* self, const Node* other);
|
||||
|
||||
void readViewFrustumPacket(const QByteArray& message);
|
||||
|
||||
@ -166,7 +167,7 @@ private:
|
||||
int _numOutOfOrderSends = 0;
|
||||
|
||||
SimpleMovingAverage _avgOtherAvatarDataRate;
|
||||
std::unordered_set<QUuid> _radiusIgnoredOthers;
|
||||
std::vector<QUuid> _radiusIgnoredOthers;
|
||||
ConicalViewFrustums _currentViewFrustums;
|
||||
|
||||
int _recentOtherAvatarsInView { 0 };
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <chrono>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/norm.hpp>
|
||||
@ -33,6 +34,8 @@
|
||||
#include "AvatarMixer.h"
|
||||
#include "AvatarMixerClientData.h"
|
||||
|
||||
namespace chrono = std::chrono;
|
||||
|
||||
void AvatarMixerSlave::configure(ConstIter begin, ConstIter end) {
|
||||
_begin = begin;
|
||||
_end = end;
|
||||
@ -209,7 +212,18 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
|
||||
_stats.jobElapsedTime += (end - start);
|
||||
}
|
||||
|
||||
AABox computeBubbleBox(const AvatarData& avatar, float bubbleExpansionFactor) {
|
||||
AABox box = avatar.getGlobalBoundingBox();
|
||||
glm::vec3 scale = box.getScale();
|
||||
scale *= bubbleExpansionFactor;
|
||||
const glm::vec3 MIN_BUBBLE_SCALE(0.3f, 1.3f, 0.3);
|
||||
scale = glm::max(scale, MIN_BUBBLE_SCALE);
|
||||
box.setScaleStayCentered(glm::max(scale, MIN_BUBBLE_SCALE));
|
||||
return box;
|
||||
}
|
||||
|
||||
void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) {
|
||||
const Node* destinationNode = node.data();
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
||||
@ -220,7 +234,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
|
||||
_stats.nodesBroadcastedTo++;
|
||||
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(node->getLinkedData());
|
||||
AvatarMixerClientData* nodeData = reinterpret_cast<AvatarMixerClientData*>(destinationNode->getLinkedData());
|
||||
|
||||
nodeData->resetInViewStats();
|
||||
|
||||
@ -242,12 +256,8 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
int traitBytesSent = 0;
|
||||
|
||||
// max number of avatarBytes per frame
|
||||
auto maxAvatarBytesPerFrame = (_maxKbpsPerNode * BYTES_PER_KILOBIT) / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND;
|
||||
int maxAvatarBytesPerFrame = int(_maxKbpsPerNode * BYTES_PER_KILOBIT / AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND);
|
||||
|
||||
// FIXME - find a way to not send the sessionID for every avatar
|
||||
int minimumBytesPerAvatar = AvatarDataPacket::AVATAR_HAS_FLAGS_SIZE + NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
int overBudgetAvatars = 0;
|
||||
|
||||
// keep track of the number of other avatars held back in this frame
|
||||
int numAvatarsHeldBack = 0;
|
||||
@ -260,66 +270,38 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
bool PALIsOpen = nodeData->getRequestsDomainListData();
|
||||
|
||||
// When this is true, the AvatarMixer will send Avatar data to a client about avatars that have ignored them
|
||||
bool getsAnyIgnored = PALIsOpen && node->getCanKick();
|
||||
bool getsAnyIgnored = PALIsOpen && destinationNode->getCanKick();
|
||||
|
||||
if (PALIsOpen) {
|
||||
// Increase minimumBytesPerAvatar if the PAL is open
|
||||
minimumBytesPerAvatar += sizeof(AvatarDataPacket::AvatarGlobalPosition) +
|
||||
sizeof(AvatarDataPacket::AudioLoudness);
|
||||
}
|
||||
// Bandwidth allowance for data that must be sent.
|
||||
int minimumBytesPerAvatar = PALIsOpen ? AvatarDataPacket::AVATAR_HAS_FLAGS_SIZE + NUM_BYTES_RFC4122_UUID +
|
||||
sizeof(AvatarDataPacket::AvatarGlobalPosition) + sizeof(AvatarDataPacket::AudioLoudness) : 0;
|
||||
|
||||
// setup a PacketList for the avatarPackets
|
||||
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
||||
static auto maxAvatarDataBytes = avatarPacketList->getMaxSegmentSize() - NUM_BYTES_RFC4122_UUID;
|
||||
|
||||
// Define the minimum bubble size
|
||||
static const glm::vec3 minBubbleSize = avatar.getSensorToWorldScale() * glm::vec3(0.3f, 1.3f, 0.3f);
|
||||
// Define the scale of the box for the current node
|
||||
glm::vec3 nodeBoxScale = (nodeData->getPosition() - nodeData->getGlobalBoundingBoxCorner()) * 2.0f * avatar.getSensorToWorldScale();
|
||||
// Set up the bounding box for the current node
|
||||
AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale);
|
||||
// Clamp the size of the bounding box to a minimum scale
|
||||
if (glm::any(glm::lessThan(nodeBoxScale, minBubbleSize))) {
|
||||
nodeBox.setScaleStayCentered(minBubbleSize);
|
||||
}
|
||||
// Quadruple the scale of both bounding boxes
|
||||
nodeBox.embiggen(4.0f);
|
||||
|
||||
|
||||
// setup list of AvatarData as well as maps to map betweeen the AvatarData and the original nodes
|
||||
std::vector<AvatarSharedPointer> avatarsToSort;
|
||||
std::unordered_map<AvatarSharedPointer, SharedNodePointer> avatarDataToNodes;
|
||||
std::unordered_map<QUuid, uint64_t> avatarEncodeTimes;
|
||||
std::for_each(_begin, _end, [&](const SharedNodePointer& otherNode) {
|
||||
// make sure this is an agent that we have avatar data for before considering it for inclusion
|
||||
if (otherNode->getType() == NodeType::Agent
|
||||
&& otherNode->getLinkedData()) {
|
||||
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(otherNode->getLinkedData());
|
||||
|
||||
AvatarSharedPointer otherAvatar = otherNodeData->getAvatarSharedPointer();
|
||||
avatarsToSort.push_back(otherAvatar);
|
||||
avatarDataToNodes[otherAvatar] = otherNode;
|
||||
QUuid id = otherAvatar->getSessionUUID();
|
||||
avatarEncodeTimes[id] = nodeData->getLastOtherAvatarEncodeTime(id);
|
||||
}
|
||||
});
|
||||
// compute node bounding box
|
||||
const float MY_AVATAR_BUBBLE_EXPANSION_FACTOR = 4.0f; // magic number determined emperically
|
||||
AABox nodeBox = computeBubbleBox(avatar, MY_AVATAR_BUBBLE_EXPANSION_FACTOR);
|
||||
|
||||
class SortableAvatar: public PrioritySortUtil::Sortable {
|
||||
public:
|
||||
SortableAvatar() = delete;
|
||||
SortableAvatar(const AvatarSharedPointer& avatar, uint64_t lastEncodeTime)
|
||||
: _avatar(avatar), _lastEncodeTime(lastEncodeTime) {}
|
||||
glm::vec3 getPosition() const override { return _avatar->getWorldPosition(); }
|
||||
SortableAvatar(const AvatarData* avatar, const Node* avatarNode, uint64_t lastEncodeTime)
|
||||
: _avatar(avatar), _node(avatarNode), _lastEncodeTime(lastEncodeTime) {}
|
||||
glm::vec3 getPosition() const override { return _avatar->getClientGlobalPosition(); }
|
||||
float getRadius() const override {
|
||||
glm::vec3 nodeBoxHalfScale = (_avatar->getWorldPosition() - _avatar->getGlobalBoundingBoxCorner() * _avatar->getSensorToWorldScale());
|
||||
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
||||
glm::vec3 nodeBoxScale = _avatar->getGlobalBoundingBox().getScale();
|
||||
return 0.5f * glm::max(nodeBoxScale.x, glm::max(nodeBoxScale.y, nodeBoxScale.z));
|
||||
}
|
||||
uint64_t getTimestamp() const override {
|
||||
return _lastEncodeTime;
|
||||
}
|
||||
AvatarSharedPointer getAvatar() const { return _avatar; }
|
||||
const Node* getNode() const { return _node; }
|
||||
|
||||
private:
|
||||
AvatarSharedPointer _avatar;
|
||||
const AvatarData* _avatar;
|
||||
const Node* _node;
|
||||
uint64_t _lastEncodeTime;
|
||||
};
|
||||
|
||||
@ -329,15 +311,18 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
AvatarData::_avatarSortCoefficientSize,
|
||||
AvatarData::_avatarSortCoefficientCenter,
|
||||
AvatarData::_avatarSortCoefficientAge);
|
||||
sortedAvatars.reserve(_end - _begin);
|
||||
|
||||
// ignore or sort
|
||||
const AvatarSharedPointer& thisAvatar = nodeData->getAvatarSharedPointer();
|
||||
for (const auto& avatar : avatarsToSort) {
|
||||
if (avatar == thisAvatar) {
|
||||
// don't echo updates to self
|
||||
for (auto listedNode = _begin; listedNode != _end; ++listedNode) {
|
||||
Node* otherNodeRaw = (*listedNode).data();
|
||||
if (otherNodeRaw->getType() != NodeType::Agent
|
||||
|| !otherNodeRaw->getLinkedData()
|
||||
|| otherNodeRaw == destinationNode) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto avatarNode = otherNodeRaw;
|
||||
|
||||
bool shouldIgnore = false;
|
||||
// We ignore other nodes for a couple of reasons:
|
||||
// 1) ignore bubbles and ignore specific node
|
||||
@ -345,53 +330,39 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
// happen if for example the avatar is connected on a desktop and sending
|
||||
// updates at ~30hz. So every 3 frames we skip a frame.
|
||||
|
||||
auto avatarNode = avatarDataToNodes[avatar];
|
||||
assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||
|
||||
const AvatarMixerClientData* avatarNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||
assert(avatarNodeData); // we can't have gotten here without avatarNode having valid data
|
||||
const AvatarMixerClientData* avatarClientNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
|
||||
assert(avatarClientNodeData); // we can't have gotten here without avatarNode having valid data
|
||||
quint64 startIgnoreCalculation = usecTimestampNow();
|
||||
|
||||
// make sure we have data for this avatar, that it isn't the same node,
|
||||
// and isn't an avatar that the viewing node has ignored
|
||||
// or that has ignored the viewing node
|
||||
if (!avatarNode->getLinkedData()
|
||||
|| avatarNode->getUUID() == node->getUUID()
|
||||
|| (node->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen)
|
||||
|| (avatarNode->isIgnoringNodeWithID(node->getUUID()) && !getsAnyIgnored)) {
|
||||
if ((destinationNode->isIgnoringNodeWithID(avatarNode->getUUID()) && !PALIsOpen)
|
||||
|| (avatarNode->isIgnoringNodeWithID(destinationNode->getUUID()) && !getsAnyIgnored)) {
|
||||
shouldIgnore = true;
|
||||
} else {
|
||||
// Check to see if the space bubble is enabled
|
||||
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
||||
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
||||
float sensorToWorldScale = avatarNodeData->getAvatarSharedPointer()->getSensorToWorldScale();
|
||||
// Define the scale of the box for the current other node
|
||||
glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f * sensorToWorldScale;
|
||||
// Set up the bounding box for the current other node
|
||||
AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||
// Clamp the size of the bounding box to a minimum scale
|
||||
if (glm::any(glm::lessThan(otherNodeBoxScale, minBubbleSize))) {
|
||||
otherNodeBox.setScaleStayCentered(minBubbleSize);
|
||||
}
|
||||
// Change the scale of both bounding boxes
|
||||
// (This is an arbitrary number determined empirically)
|
||||
otherNodeBox.embiggen(2.4f);
|
||||
|
||||
if (destinationNode->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
||||
// Perform the collision check between the two bounding boxes
|
||||
const float OTHER_AVATAR_BUBBLE_EXPANSION_FACTOR = 2.4f; // magic number determined empirically
|
||||
AABox otherNodeBox = computeBubbleBox(avatarClientNodeData->getAvatar(), OTHER_AVATAR_BUBBLE_EXPANSION_FACTOR);
|
||||
if (nodeBox.touches(otherNodeBox)) {
|
||||
nodeData->ignoreOther(node, avatarNode);
|
||||
nodeData->ignoreOther(destinationNode, avatarNode);
|
||||
shouldIgnore = !getsAnyIgnored;
|
||||
}
|
||||
}
|
||||
// Not close enough to ignore
|
||||
if (!shouldIgnore) {
|
||||
nodeData->removeFromRadiusIgnoringSet(node, avatarNode->getUUID());
|
||||
nodeData->removeFromRadiusIgnoringSet(avatarNode->getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldIgnore) {
|
||||
AvatarDataSequenceNumber lastSeqToReceiver = nodeData->getLastBroadcastSequenceNumber(avatarNode->getUUID());
|
||||
AvatarDataSequenceNumber lastSeqFromSender = avatarNodeData->getLastReceivedSequenceNumber();
|
||||
AvatarDataSequenceNumber lastSeqFromSender = avatarClientNodeData->getLastReceivedSequenceNumber();
|
||||
|
||||
// FIXME - This code does appear to be working. But it seems brittle.
|
||||
// It supports determining if the frame of data for this "other"
|
||||
@ -416,12 +387,10 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
|
||||
if (!shouldIgnore) {
|
||||
// sort this one for later
|
||||
uint64_t lastEncodeTime = 0;
|
||||
std::unordered_map<QUuid, uint64_t>::const_iterator itr = avatarEncodeTimes.find(avatar->getSessionUUID());
|
||||
if (itr != avatarEncodeTimes.end()) {
|
||||
lastEncodeTime = itr->second;
|
||||
}
|
||||
sortedAvatars.push(SortableAvatar(avatar, lastEncodeTime));
|
||||
const AvatarData* avatarNodeData = avatarClientNodeData->getConstAvatarData();
|
||||
auto lastEncodeTime = nodeData->getLastOtherAvatarEncodeTime(avatarNodeData->getSessionUUID());
|
||||
|
||||
sortedAvatars.push(SortableAvatar(avatarNodeData, avatarNode, lastEncodeTime));
|
||||
}
|
||||
}
|
||||
|
||||
@ -429,19 +398,31 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
|
||||
int remainingAvatars = (int)sortedAvatars.size();
|
||||
auto traitsPacketList = NLPacketList::create(PacketType::BulkAvatarTraits, QByteArray(), true, true);
|
||||
while (!sortedAvatars.empty()) {
|
||||
const auto avatarData = sortedAvatars.top().getAvatar();
|
||||
sortedAvatars.pop();
|
||||
remainingAvatars--;
|
||||
|
||||
auto otherNode = avatarDataToNodes[avatarData];
|
||||
const auto& sortedAvatarVector = sortedAvatars.getSortedVector();
|
||||
for (const auto& sortedAvatar : sortedAvatarVector) {
|
||||
const Node* otherNode = sortedAvatar.getNode();
|
||||
auto lastEncodeForOther = sortedAvatar.getTimestamp();
|
||||
|
||||
assert(otherNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||
|
||||
// NOTE: Here's where we determine if we are over budget and drop to bare minimum data
|
||||
AvatarData::AvatarDataDetail detail = AvatarData::NoData;
|
||||
|
||||
// NOTE: Here's where we determine if we are over budget and drop remaining avatars,
|
||||
// or send minimal avatar data in uncommon case of PALIsOpen.
|
||||
int minimRemainingAvatarBytes = minimumBytesPerAvatar * remainingAvatars;
|
||||
bool overBudget = (identityBytesSent + numAvatarDataBytes + minimRemainingAvatarBytes) > maxAvatarBytesPerFrame;
|
||||
if (overBudget) {
|
||||
if (PALIsOpen) {
|
||||
_stats.overBudgetAvatars++;
|
||||
detail = AvatarData::PALMinimum;
|
||||
} else {
|
||||
_stats.overBudgetAvatars += remainingAvatars;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
quint64 startAvatarDataPacking = usecTimestampNow();
|
||||
auto startAvatarDataPacking = chrono::high_resolution_clock::now();
|
||||
|
||||
++numOtherAvatars;
|
||||
|
||||
@ -458,32 +439,18 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
nodeData->setLastBroadcastTime(otherNode->getUUID(), usecTimestampNow());
|
||||
}
|
||||
|
||||
// determine if avatar is in view which determines how much data to send
|
||||
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
||||
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f * otherAvatar->getSensorToWorldScale();
|
||||
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
||||
// Typically all out-of-view avatars but such avatars' priorities will rise with time:
|
||||
bool isLowerPriority = sortedAvatar.getPriority() <= OUT_OF_VIEW_THRESHOLD;
|
||||
|
||||
// start a new segment in the PacketList for this avatar
|
||||
avatarPacketList->startSegment();
|
||||
|
||||
AvatarData::AvatarDataDetail detail;
|
||||
|
||||
if (overBudget) {
|
||||
overBudgetAvatars++;
|
||||
_stats.overBudgetAvatars++;
|
||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::NoData;
|
||||
} else if (!isInView) {
|
||||
if (isLowerPriority) {
|
||||
detail = PALIsOpen ? AvatarData::PALMinimum : AvatarData::MinimumData;
|
||||
nodeData->incrementAvatarOutOfView();
|
||||
} else {
|
||||
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO
|
||||
? AvatarData::SendAllData : AvatarData::CullSmallData;
|
||||
} else if (!overBudget) {
|
||||
detail = distribution(generator) < AVATAR_SEND_FULL_UPDATE_RATIO ? AvatarData::SendAllData : AvatarData::CullSmallData;
|
||||
nodeData->incrementAvatarInView();
|
||||
}
|
||||
|
||||
bool includeThisAvatar = true;
|
||||
auto lastEncodeForOther = nodeData->getLastOtherAvatarEncodeTime(otherNode->getUUID());
|
||||
QVector<JointData>& lastSentJointsForOther = nodeData->getLastOtherAvatarSentJoints(otherNode->getUUID());
|
||||
|
||||
lastSentJointsForOther.resize(otherAvatar->getJointCount());
|
||||
@ -493,14 +460,14 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
AvatarDataPacket::HasFlags hasFlagsOut; // the result of the toByteArray
|
||||
bool dropFaceTracking = false;
|
||||
|
||||
quint64 start = usecTimestampNow();
|
||||
auto startSerialize = chrono::high_resolution_clock::now();
|
||||
QByteArray bytes = otherAvatar->toByteArray(detail, lastEncodeForOther, lastSentJointsForOther,
|
||||
hasFlagsOut, dropFaceTracking, distanceAdjust, viewerPosition,
|
||||
&lastSentJointsForOther);
|
||||
quint64 end = usecTimestampNow();
|
||||
_stats.toByteArrayElapsedTime += (end - start);
|
||||
auto endSerialize = chrono::high_resolution_clock::now();
|
||||
_stats.toByteArrayElapsedTime +=
|
||||
(quint64) chrono::duration_cast<chrono::microseconds>(endSerialize - startSerialize).count();
|
||||
|
||||
static auto maxAvatarDataBytes = avatarPacketList->getMaxSegmentSize() - NUM_BYTES_RFC4122_UUID;
|
||||
if (bytes.size() > maxAvatarDataBytes) {
|
||||
qCWarning(avatars) << "otherAvatar.toByteArray() for" << otherNode->getUUID()
|
||||
<< "resulted in very large buffer of" << bytes.size() << "bytes - dropping facial data";
|
||||
@ -526,8 +493,11 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
}
|
||||
|
||||
if (includeThisAvatar) {
|
||||
// start a new segment in the PacketList for this avatar
|
||||
avatarPacketList->startSegment();
|
||||
numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122());
|
||||
numAvatarDataBytes += avatarPacketList->write(bytes);
|
||||
avatarPacketList->endSegment();
|
||||
|
||||
if (detail != AvatarData::NoData) {
|
||||
_stats.numOthersIncluded++;
|
||||
@ -545,15 +515,13 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
// It would be nice if we could tweak its future sort priority to put it at the back of the list.
|
||||
}
|
||||
|
||||
avatarPacketList->endSegment();
|
||||
|
||||
quint64 endAvatarDataPacking = usecTimestampNow();
|
||||
_stats.avatarDataPackingElapsedTime += (endAvatarDataPacking - startAvatarDataPacking);
|
||||
auto endAvatarDataPacking = chrono::high_resolution_clock::now();
|
||||
_stats.avatarDataPackingElapsedTime +=
|
||||
(quint64) chrono::duration_cast<chrono::microseconds>(endAvatarDataPacking - startAvatarDataPacking).count();
|
||||
|
||||
// use helper to add any changed traits to our packet list
|
||||
traitBytesSent += addChangedTraitsToBulkPacket(nodeData, otherNodeData, *traitsPacketList);
|
||||
|
||||
traitsPacketList->getDataSize();
|
||||
remainingAvatars--;
|
||||
}
|
||||
|
||||
quint64 startPacketSending = usecTimestampNow();
|
||||
@ -565,7 +533,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
_stats.numBytesSent += numAvatarDataBytes;
|
||||
|
||||
// send the avatar data PacketList
|
||||
nodeList->sendPacketList(std::move(avatarPacketList), *node);
|
||||
nodeList->sendPacketList(std::move(avatarPacketList), *destinationNode);
|
||||
|
||||
// record the bytes sent for other avatar data in the AvatarMixerClientData
|
||||
nodeData->recordSentAvatarData(numAvatarDataBytes);
|
||||
@ -575,7 +543,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||
|
||||
if (traitsPacketList->getNumPackets() >= 1) {
|
||||
// send the traits packet list
|
||||
nodeList->sendPacketList(std::move(traitsPacketList), *node);
|
||||
nodeList->sendPacketList(std::move(traitsPacketList), *destinationNode);
|
||||
}
|
||||
|
||||
// record the number of avatars held back this frame
|
||||
|
@ -145,3 +145,15 @@ void ScriptableAvatar::update(float deltatime) {
|
||||
|
||||
_clientTraitsHandler->sendChangedTraitsToMixer();
|
||||
}
|
||||
|
||||
void ScriptableAvatar::setHasProceduralBlinkFaceMovement(bool hasProceduralBlinkFaceMovement) {
|
||||
_headData->setHasProceduralBlinkFaceMovement(hasProceduralBlinkFaceMovement);
|
||||
}
|
||||
|
||||
void ScriptableAvatar::setHasProceduralEyeFaceMovement(bool hasProceduralEyeFaceMovement) {
|
||||
_headData->setHasProceduralEyeFaceMovement(hasProceduralEyeFaceMovement);
|
||||
}
|
||||
|
||||
void ScriptableAvatar::setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement) {
|
||||
_headData->setHasAudioEnabledFaceMovement(hasAudioEnabledFaceMovement);
|
||||
}
|
||||
|
@ -157,9 +157,16 @@ public:
|
||||
|
||||
virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking = false) override;
|
||||
|
||||
void setHasProceduralBlinkFaceMovement(bool hasProceduralBlinkFaceMovement);
|
||||
bool getHasProceduralBlinkFaceMovement() const override { return _headData->getHasProceduralBlinkFaceMovement(); }
|
||||
void setHasProceduralEyeFaceMovement(bool hasProceduralEyeFaceMovement);
|
||||
bool getHasProceduralEyeFaceMovement() const override { return _headData->getHasProceduralEyeFaceMovement(); }
|
||||
void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement);
|
||||
bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); }
|
||||
|
||||
private slots:
|
||||
void update(float deltatime);
|
||||
|
||||
|
||||
private:
|
||||
AnimationPointer _animation;
|
||||
AnimationDetails _animationDetails;
|
||||
|
@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content)
|
||||
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC72.zip
|
||||
URL_MD5 b1d8faf9266bfbff88274a484911eb99
|
||||
URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC73.zip
|
||||
URL_MD5 0c5edfb63cafb042311d3cf25261fbf2
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
|
@ -9,7 +9,6 @@
|
||||
#
|
||||
|
||||
macro(AUTOSCRIBE_SHADER)
|
||||
message(STATUS "Processing shader ${SHADER_FILE}")
|
||||
unset(SHADER_INCLUDE_FILES)
|
||||
# Grab include files
|
||||
foreach(includeFile ${ARGN})
|
||||
|
@ -8,6 +8,5 @@
|
||||
macro(TARGET_JSON)
|
||||
add_dependency_external_projects(json)
|
||||
find_package(JSON REQUIRED)
|
||||
message("JSON_INCLUDE_DIRS ${JSON_INCLUDE_DIRS}")
|
||||
target_include_directories(${TARGET_NAME} PUBLIC ${JSON_INCLUDE_DIRS})
|
||||
endmacro()
|
@ -1110,7 +1110,36 @@ function moveTableRow(row, move_up) {
|
||||
}
|
||||
|
||||
// we need to fire a change event on one of the remaining inputs so that the sidebar badge is updated
|
||||
badgeForDifferences($(table))
|
||||
badgeForDifferences($(table));
|
||||
|
||||
// figure out which group this row is in
|
||||
var panelParentID = row.closest('.panel').attr('id');
|
||||
|
||||
// get the short name for the setting from the table
|
||||
var tableShortName = row.closest('table').data('short-name');
|
||||
|
||||
var changed = tableHasChanged(panelParentID, tableShortName);
|
||||
$(table).find('.' + Settings.DATA_ROW_CLASS).each(function(){
|
||||
var hiddenInput = $(this).find('td.' + Settings.DATA_COL_CLASS + ' input');
|
||||
if (changed) {
|
||||
hiddenInput.attr('data-changed', true);
|
||||
} else {
|
||||
hiddenInput.removeAttr('data-changed');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function tableHasChanged(panelParentID, tableShortName) {
|
||||
// get a JSON representation of that section
|
||||
var panelSettingJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID][tableShortName]
|
||||
if (Settings.initialValues[panelParentID]) {
|
||||
var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName]
|
||||
} else {
|
||||
var initialPanelSettingJSON = {};
|
||||
}
|
||||
|
||||
return !_.isEqual(panelSettingJSON, initialPanelSettingJSON);
|
||||
}
|
||||
|
||||
function updateDataChangedForSiblingRows(row, forceTrue) {
|
||||
@ -1123,16 +1152,8 @@ function updateDataChangedForSiblingRows(row, forceTrue) {
|
||||
// get the short name for the setting from the table
|
||||
var tableShortName = row.closest('table').data('short-name')
|
||||
|
||||
// get a JSON representation of that section
|
||||
var panelSettingJSON = form2js(panelParentID, ".", false, cleanupFormValues, true)[panelParentID][tableShortName]
|
||||
if (Settings.initialValues[panelParentID]) {
|
||||
var initialPanelSettingJSON = Settings.initialValues[panelParentID][tableShortName]
|
||||
} else {
|
||||
var initialPanelSettingJSON = {};
|
||||
}
|
||||
|
||||
// if they are equal, we don't need data-changed
|
||||
isTrue = !_.isEqual(panelSettingJSON, initialPanelSettingJSON)
|
||||
isTrue = tableHasChanged(panelParentID, tableShortName);
|
||||
} else {
|
||||
isTrue = true
|
||||
}
|
||||
@ -1140,9 +1161,9 @@ function updateDataChangedForSiblingRows(row, forceTrue) {
|
||||
row.siblings('.' + Settings.DATA_ROW_CLASS).each(function(){
|
||||
var hiddenInput = $(this).find('td.' + Settings.DATA_COL_CLASS + ' input')
|
||||
if (isTrue) {
|
||||
hiddenInput.attr('data-changed', isTrue)
|
||||
hiddenInput.attr('data-changed', isTrue);
|
||||
} else {
|
||||
hiddenInput.removeAttr('data-changed')
|
||||
hiddenInput.removeAttr('data-changed');
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -2906,7 +2906,7 @@ void DomainServer::updateReplicationNodes(ReplicationServerDirection direction)
|
||||
// collect them in a vector to separately remove them with handleKillNode (since eachNode has a read lock and
|
||||
// we cannot recursively take the write lock required by handleKillNode)
|
||||
std::vector<SharedNodePointer> nodesToKill;
|
||||
nodeList->eachNode([this, direction, replicationNodesInSettings, replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) {
|
||||
nodeList->eachNode([direction, replicationNodesInSettings, replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) {
|
||||
if ((direction == Upstream && NodeType::isUpstream(otherNode->getType()))
|
||||
|| (direction == Downstream && NodeType::isDownstream(otherNode->getType()))) {
|
||||
bool nodeInSettings = find(replicationNodesInSettings.cbegin(), replicationNodesInSettings.cend(),
|
||||
|
@ -332,6 +332,10 @@ if (APPLE)
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${PROJECT_SOURCE_DIR}/resources/fonts"
|
||||
"${RESOURCES_DEV_DIR}/fonts"
|
||||
# add redirect json to macOS builds.
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||
)
|
||||
|
||||
# call the fixup_interface macro to add required bundling commands for installation
|
||||
@ -360,6 +364,9 @@ else()
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/tutorial.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/tutorial.json"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different
|
||||
"${PROJECT_SOURCE_DIR}/resources/serverless/redirect.json"
|
||||
"${RESOURCES_DEV_DIR}/serverless/redirect.json"
|
||||
# copy JSDoc files beside the executable
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_SOURCE_DIR}/tools/jsdoc/out"
|
||||
|
BIN
interface/resources/avatar/animations/jog_bwd.fbx
Normal file
BIN
interface/resources/avatar/animations/jump_standing_launch.fbx
Normal file
BIN
interface/resources/avatar/animations/run_bwd.fbx
Normal file
@ -585,149 +585,188 @@
|
||||
"states": [
|
||||
{
|
||||
"id": "idle",
|
||||
"interpTarget": 0,
|
||||
"interpDuration": 4,
|
||||
"interpTarget": 20,
|
||||
"interpDuration": 8,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isMovingForward", "state": "idleToWalkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "idleToWalkFwd",
|
||||
"interpTarget": 10,
|
||||
"interpDuration": 4,
|
||||
"interpType": "snapshotPrev",
|
||||
"interpTarget": 12,
|
||||
"interpDuration": 8,
|
||||
"transitions": [
|
||||
{ "var": "idleToWalkFwdOnDone", "state": "walkFwd" },
|
||||
{ "var": "idleToWalkFwdOnDone", "state": "WALKFWD" },
|
||||
{ "var": "isNotMoving", "state": "idle" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "idleSettle",
|
||||
"interpTarget": 10,
|
||||
"interpDuration": 10,
|
||||
"interpTarget": 15,
|
||||
"interpDuration": 8,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{"var": "idleSettleOnDone", "state": "idle" },
|
||||
{"var": "isMovingForward", "state": "idleToWalkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{"var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" }
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "walkFwd",
|
||||
"interpTarget": 16,
|
||||
"interpDuration": 6,
|
||||
"id": "WALKFWD",
|
||||
"interpTarget": 35,
|
||||
"interpDuration": 10,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "walkBwd",
|
||||
"interpTarget": 8,
|
||||
"interpDuration": 6,
|
||||
"id": "WALKBWD",
|
||||
"interpTarget": 35,
|
||||
"interpDuration": 10,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "strafeRight",
|
||||
"interpTarget": 5,
|
||||
"id": "STRAFERIGHT",
|
||||
"interpTarget": 25,
|
||||
"interpDuration": 8,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "strafeLeft",
|
||||
"interpTarget": 5,
|
||||
"id": "STRAFELEFT",
|
||||
"interpTarget": 25,
|
||||
"interpDuration": 8,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turnRight",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 8,
|
||||
"transitions": [
|
||||
{ "var": "isNotTurning", "state": "idle" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turnLeft",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 8,
|
||||
"transitions": [
|
||||
{ "var": "isNotTurning", "state": "idle" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
@ -739,18 +778,18 @@
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" }
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" }
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -760,60 +799,18 @@
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotMoving", "state": "idleSettle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turnRight",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 8,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotTurning", "state": "idle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "turnLeft",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 8,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotTurning", "state": "idle" },
|
||||
{ "var": "isMovingForward", "state": "walkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" }
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -826,79 +823,79 @@
|
||||
},
|
||||
{
|
||||
"id": "takeoffStand",
|
||||
"interpTarget": 0,
|
||||
"interpDuration": 6,
|
||||
"interpTarget": 2,
|
||||
"interpDuration": 2,
|
||||
"transitions": [
|
||||
{ "var": "isNotTakeoff", "state": "inAirStand" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "takeoffRun",
|
||||
"interpTarget": 0,
|
||||
"interpDuration": 6,
|
||||
"id": "TAKEOFFRUN",
|
||||
"interpTarget": 2,
|
||||
"interpDuration": 2,
|
||||
"transitions": [
|
||||
{ "var": "isNotTakeoff", "state": "inAirRun" }
|
||||
{ "var": "isNotTakeoff", "state": "INAIRRUN" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "inAirStand",
|
||||
"interpTarget": 0,
|
||||
"interpDuration": 6,
|
||||
"interpTarget": 3,
|
||||
"interpDuration": 3,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotInAir", "state": "landStandImpact" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "inAirRun",
|
||||
"interpTarget": 0,
|
||||
"interpDuration": 6,
|
||||
"id": "INAIRRUN",
|
||||
"interpTarget": 3,
|
||||
"interpDuration": 3,
|
||||
"interpType": "snapshotPrev",
|
||||
"transitions": [
|
||||
{ "var": "isNotInAir", "state": "landRun" }
|
||||
{ "var": "isNotInAir", "state": "WALKFWD" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "landStandImpact",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 4,
|
||||
"interpTarget": 1,
|
||||
"interpDuration": 1,
|
||||
"transitions": [
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "landStandImpactOnDone", "state": "landStand" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "landStand",
|
||||
"interpTarget": 0,
|
||||
"interpTarget": 1,
|
||||
"interpDuration": 1,
|
||||
"transitions": [
|
||||
{ "var": "isMovingForward", "state": "idleToWalkFwd" },
|
||||
{ "var": "isMovingBackward", "state": "walkBwd" },
|
||||
{ "var": "isMovingRight", "state": "strafeRight" },
|
||||
{ "var": "isMovingLeft", "state": "strafeLeft" },
|
||||
{ "var": "isMovingForward", "state": "WALKFWD" },
|
||||
{ "var": "isMovingBackward", "state": "WALKBWD" },
|
||||
{ "var": "isMovingRight", "state": "STRAFERIGHT" },
|
||||
{ "var": "isMovingLeft", "state": "STRAFELEFT" },
|
||||
{ "var": "isTurningRight", "state": "turnRight" },
|
||||
{ "var": "isTurningLeft", "state": "turnLeft" },
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "isInAirStand", "state": "inAirStand" },
|
||||
{ "var": "isInAirRun", "state": "inAirRun" },
|
||||
{ "var": "isInAirRun", "state": "INAIRRUN" },
|
||||
{ "var": "landStandOnDone", "state": "idle" },
|
||||
{ "var": "isMovingRightHmd", "state": "strafeRightHmd" },
|
||||
{ "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "landRun",
|
||||
"interpTarget": 1,
|
||||
"interpDuration": 7,
|
||||
"id": "LANDRUN",
|
||||
"interpTarget": 2,
|
||||
"interpDuration": 2,
|
||||
"transitions": [
|
||||
{ "var": "isFlying", "state": "fly" },
|
||||
{ "var": "isTakeoffStand", "state": "takeoffStand" },
|
||||
{ "var": "isTakeoffRun", "state": "takeoffRun" },
|
||||
{ "var": "landRunOnDone", "state": "walkFwd" }
|
||||
{ "var": "isTakeoffRun", "state": "TAKEOFFRUN" },
|
||||
{ "var": "landRunOnDone", "state": "WALKFWD" }
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -913,7 +910,7 @@
|
||||
{
|
||||
"id": "idleStand",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"interpDuration": 10,
|
||||
"transitions": [
|
||||
{ "var": "isTalking", "state": "idleTalk" }
|
||||
]
|
||||
@ -921,7 +918,7 @@
|
||||
{
|
||||
"id": "idleTalk",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"interpDuration": 10,
|
||||
"transitions": [
|
||||
{ "var": "notIsTalking", "state": "idleStand" }
|
||||
]
|
||||
@ -956,12 +953,12 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "walkFwd",
|
||||
"id": "WALKFWD",
|
||||
"type": "blendLinearMove",
|
||||
"data": {
|
||||
"alpha": 0.0,
|
||||
"desiredSpeed": 1.4,
|
||||
"characteristicSpeeds": [0.5, 1.5, 2.5, 3.2, 4.5],
|
||||
"characteristicSpeeds": [0.5, 1.8, 2.3, 3.2, 4.5],
|
||||
"alphaVar": "moveForwardAlpha",
|
||||
"desiredSpeedVar": "moveForwardSpeed"
|
||||
},
|
||||
@ -984,7 +981,7 @@
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/walk_fwd.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 35.0,
|
||||
"endFrame": 30.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
@ -1046,25 +1043,25 @@
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/settle_to_idle.fbx",
|
||||
"startFrame": 1.0,
|
||||
"endFrame": 48.0,
|
||||
"endFrame": 59.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "walkBwd",
|
||||
"id": "WALKBWD",
|
||||
"type": "blendLinearMove",
|
||||
"data": {
|
||||
"alpha": 0.0,
|
||||
"desiredSpeed": 1.4,
|
||||
"characteristicSpeeds": [0.6, 1.7],
|
||||
"characteristicSpeeds": [0.6, 1.6, 2.3, 3.1],
|
||||
"alphaVar": "moveBackwardAlpha",
|
||||
"desiredSpeedVar": "moveBackwardSpeed"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "walkBwdShort",
|
||||
"id": "walkBwdShort_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/walk_short_bwd.fbx",
|
||||
@ -1076,7 +1073,7 @@
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "walkBwdNormal",
|
||||
"id": "walkBwdFast_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/walk_bwd_fast.fbx",
|
||||
@ -1086,6 +1083,30 @@
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "jogBwd_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jog_bwd.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 24.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "runBwd_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/run_bwd.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 16.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -1115,18 +1136,18 @@
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "strafeLeft",
|
||||
"id": "STRAFELEFT",
|
||||
"type": "blendLinearMove",
|
||||
"data": {
|
||||
"alpha": 0.0,
|
||||
"desiredSpeed": 1.4,
|
||||
"characteristicSpeeds": [0, 0.5, 1.5, 2.6, 3.0],
|
||||
"characteristicSpeeds": [0.1, 0.5, 1.0, 2.6, 3.0],
|
||||
"alphaVar": "moveLateralAlpha",
|
||||
"desiredSpeedVar": "moveLateralSpeed"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "strafeLeftShort_c",
|
||||
"id": "strafeLeftShortStep_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/side_step_short_left.fbx",
|
||||
@ -1138,7 +1159,7 @@
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "strafeLeft_c",
|
||||
"id": "strafeLeftStep_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/side_step_left.fbx",
|
||||
@ -1150,19 +1171,19 @@
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "strafeLeftAnim_c",
|
||||
"id": "strafeLeftWalk_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/walk_left.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 33.0,
|
||||
"endFrame": 35.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "strafeLeftFast_c",
|
||||
"id": "strafeLeftWalkFast_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/walk_left_fast.fbx",
|
||||
@ -1188,17 +1209,17 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "strafeRight",
|
||||
"id": "STRAFERIGHT",
|
||||
"type": "blendLinearMove",
|
||||
"data": {
|
||||
"alpha": 0.0,
|
||||
"desiredSpeed": 1.4,
|
||||
"characteristicSpeeds": [0, 0.5, 1.5, 2.6, 3.0],
|
||||
"characteristicSpeeds": [0.1, 0.5, 1.0, 2.6, 3.0],
|
||||
"alphaVar": "moveLateralAlpha",
|
||||
"desiredSpeedVar": "moveLateralSpeed"
|
||||
},
|
||||
"children": [ {
|
||||
"id": "stepRightShort_c",
|
||||
"id": "strafeRightShortStep_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/side_step_short_left.fbx",
|
||||
@ -1211,7 +1232,7 @@
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "stepRight_c",
|
||||
"id": "strafeRightStep_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/side_step_left.fbx",
|
||||
@ -1224,12 +1245,12 @@
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "strafeRight_c",
|
||||
"id": "strafeRightWalk_c",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/walk_left.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 33.0,
|
||||
"endFrame": 35.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true,
|
||||
"mirrorFlag": true
|
||||
@ -1381,22 +1402,22 @@
|
||||
"id": "takeoffStand",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jump_standing_takeoff.fbx",
|
||||
"startFrame": 17.0,
|
||||
"endFrame": 25.0,
|
||||
"url": "qrc:///avatar/animations/jump_standing_launch.fbx",
|
||||
"startFrame": 2.0,
|
||||
"endFrame": 16.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "takeoffRun",
|
||||
"id": "TAKEOFFRUN",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jump_takeoff.fbx",
|
||||
"startFrame": 1.0,
|
||||
"endFrame": 2.5,
|
||||
"timeScale": 0.01,
|
||||
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||
"startFrame": 4.0,
|
||||
"endFrame": 15.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
@ -1416,7 +1437,7 @@
|
||||
"url": "qrc:///avatar/animations/jump_standing_apex.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 0.0,
|
||||
"timeScale": 0.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
@ -1448,7 +1469,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "inAirRun",
|
||||
"id": "INAIRRUN",
|
||||
"type": "blendLinear",
|
||||
"data": {
|
||||
"alpha": 0.0,
|
||||
@ -1459,10 +1480,10 @@
|
||||
"id": "inAirRunPreApex",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jump_in_air.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 0.0,
|
||||
"timeScale": 0.0,
|
||||
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||
"startFrame": 16.0,
|
||||
"endFrame": 16.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
@ -1471,9 +1492,9 @@
|
||||
"id": "inAirRunApex",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jump_in_air.fbx",
|
||||
"startFrame": 6.0,
|
||||
"endFrame": 6.0,
|
||||
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||
"startFrame": 22.0,
|
||||
"endFrame": 22.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
@ -1483,9 +1504,9 @@
|
||||
"id": "inAirRunPostApex",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jump_in_air.fbx",
|
||||
"startFrame": 11.0,
|
||||
"endFrame": 11.0,
|
||||
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||
"startFrame": 33.0,
|
||||
"endFrame": 33.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
@ -1497,7 +1518,7 @@
|
||||
"id": "landStandImpact",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jump_standing_land.fbx",
|
||||
"url": "qrc:///avatar/animations/jump_standing_land_settle.fbx",
|
||||
"startFrame": 1.0,
|
||||
"endFrame": 6.0,
|
||||
"timeScale": 1.0,
|
||||
@ -1509,22 +1530,22 @@
|
||||
"id": "landStand",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jump_standing_land.fbx",
|
||||
"url": "qrc:///avatar/animations/jump_standing_land_settle.fbx",
|
||||
"startFrame": 6.0,
|
||||
"endFrame": 28.0,
|
||||
"endFrame": 68.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "landRun",
|
||||
"id": "LANDRUN",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/jump_land.fbx",
|
||||
"startFrame": 1.0,
|
||||
"endFrame": 6.0,
|
||||
"timeScale": 0.65,
|
||||
"url": "qrc:///avatar/animations/jump_running_launch_land.fbx",
|
||||
"startFrame": 29.0,
|
||||
"endFrame": 40.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
|
57
interface/resources/icons/tablet-icons/goto-a-msg.svg
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="goto-a.svg"><metadata
|
||||
id="metadata14"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs12" /><sodipodi:namedview
|
||||
pagecolor="#ff0000"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="852"
|
||||
inkscape:window-height="480"
|
||||
id="namedview10"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4.72"
|
||||
inkscape:cx="25"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" /><style
|
||||
type="text/css"
|
||||
id="style4">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#EF3B4E;}
|
||||
</style>
|
||||
<circle class="st1" cx="44.1" cy="6" r="5.6"/>
|
||||
<g
|
||||
id="Layer_2" /><g
|
||||
id="Layer_1"
|
||||
style="fill:#000000;fill-opacity:1"><path
|
||||
class="st0"
|
||||
d="M47.2,41.3l-9.1-9.1c-0.8-0.8-1.9-1.1-3-1l-2.4-2.4c1.8-2.6,2.8-5.7,2.8-9c0-8.9-7.2-16.1-16.1-16.1 S3.3,11,3.3,19.8c0,8.9,7.2,16.1,16.1,16.1c4.1,0,7.8-1.5,10.6-4l2.2,2.2c-0.2,1.1,0.1,2.2,1,3l9.1,9.1c1.4,1.4,3.6,1.4,4.9,0 C48.5,44.9,48.5,42.7,47.2,41.3z M19.4,32.2c-6.8,0-12.3-5.5-12.3-12.3c0-6.8,5.5-12.3,12.3-12.3s12.3,5.5,12.3,12.3 C31.8,26.6,26.2,32.2,19.4,32.2z"
|
||||
id="path8"
|
||||
style="fill:#000000;fill-opacity:1" /></g></svg>
|
After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 911 B After Width: | Height: | Size: 911 B |
83
interface/resources/icons/tablet-icons/people-a-msg.svg
Normal file
@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 50 50"
|
||||
style="enable-background:new 0 0 50 50;"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="people-a.svg"><metadata
|
||||
id="metadata24"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs22" /><sodipodi:namedview
|
||||
pagecolor="#ff0000"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="852"
|
||||
inkscape:window-height="480"
|
||||
id="namedview20"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4.72"
|
||||
inkscape:cx="25"
|
||||
inkscape:cy="25"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" /><style
|
||||
type="text/css"
|
||||
id="style4">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#EF3B4E;}
|
||||
</style>
|
||||
<circle class="st1" cx="44.1" cy="6" r="5.6"/>
|
||||
<g
|
||||
id="Layer_2" /><g
|
||||
id="Layer_1"
|
||||
style="fill:#000000;fill-opacity:1"><circle
|
||||
class="st0"
|
||||
cx="25.6"
|
||||
cy="14.8"
|
||||
r="8.1"
|
||||
id="circle8"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M31.4,27h-11c-4.6,0-8.2,3.9-8.2,8.5v4.3c3.8,2.8,8.1,4.5,13.1,4.5c5.6,0,10.6-2.1,14.4-5.6v-3.2 C39.6,30.9,35.9,27,31.4,27z"
|
||||
id="path10"
|
||||
style="fill:#000000;fill-opacity:1" /><circle
|
||||
class="st0"
|
||||
cx="41.6"
|
||||
cy="17.1"
|
||||
r="3.5"
|
||||
id="circle12"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M43.9,23.9h-4.1c-0.9,0-1.7,0.4-2.3,1c1.2,0.6,2.3,1.6,3.1,2.5c1,1.2,1.5,2.7,1.7,4.3c0.3,0.9,0.4,1.8,0.2,2.8 v0.6c1.6-2.2,3.3-6,4-8.1v-0.3C46.5,25.7,45.3,23.9,43.9,23.9z"
|
||||
id="path14"
|
||||
style="fill:#000000;fill-opacity:1" /><circle
|
||||
class="st0"
|
||||
cx="9.4"
|
||||
cy="18"
|
||||
r="3.5"
|
||||
id="circle16"
|
||||
style="fill:#000000;fill-opacity:1" /><path
|
||||
class="st0"
|
||||
d="M8.5,35.7c-0.1-0.7-0.1-1.4,0-2.1l0.1-0.2c0-0.2,0-0.4,0-0.6c0-0.2,0-0.3,0.1-0.5c0-0.2,0-0.3,0-0.5 c0.2-2.1,1.6-4.4,3.2-5.7c0.4-0.4,0.9-0.6,1.4-0.9c-0.5-0.5-1.3-0.7-2-0.7H7c-1.4,0-2.6,1.8-2.4,2.7v0.3 C5.1,29.8,6.8,33.5,8.5,35.7z"
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1" /></g></svg>
|
After Width: | Height: | Size: 2.9 KiB |
24
interface/resources/icons/tablet-icons/people-i-msg.svg
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#EF3B4E;}
|
||||
</style>
|
||||
<circle class="st1" cx="44.1" cy="6" r="5.6"/>
|
||||
<g id="Layer_2">
|
||||
</g>
|
||||
<g id="Layer_1">
|
||||
<circle class="st0" cx="25.6" cy="14.8" r="8.1"/>
|
||||
<path class="st0" d="M31.4,27h-11c-4.6,0-8.2,3.9-8.2,8.5v4.3c3.8,2.8,8.1,4.5,13.1,4.5c5.6,0,10.6-2.1,14.4-5.6v-3.2
|
||||
C39.6,30.9,35.9,27,31.4,27z"/>
|
||||
<circle class="st0" cx="41.6" cy="17.1" r="3.5"/>
|
||||
<path class="st0" d="M43.9,23.9h-4.1c-0.9,0-1.7,0.4-2.3,1c1.2,0.6,2.3,1.6,3.1,2.5c1,1.2,1.5,2.7,1.7,4.3c0.3,0.9,0.4,1.8,0.2,2.8
|
||||
v0.6c1.6-2.2,3.3-6,4-8.1v-0.3C46.5,25.7,45.3,23.9,43.9,23.9z"/>
|
||||
<circle class="st0" cx="9.4" cy="18" r="3.5"/>
|
||||
<path class="st0" d="M8.5,35.7c-0.1-0.7-0.1-1.4,0-2.1l0.1-0.2c0-0.2,0-0.4,0-0.6c0-0.2,0-0.3,0.1-0.5c0-0.2,0-0.3,0-0.5
|
||||
c0.2-2.1,1.6-4.4,3.2-5.7c0.4-0.4,0.9-0.6,1.4-0.9c-0.5-0.5-1.3-0.7-2-0.7H7c-1.4,0-2.6,1.8-2.4,2.7v0.3
|
||||
C5.1,29.8,6.8,33.5,8.5,35.7z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
6
interface/resources/icons/tablet-icons/wallet-a-msg.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 96 96" style="enable-background:new 0 0 96 96;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st1{fill:#EF3B4E;}
|
||||
</style>
|
||||
<circle class="st1" cx="84.6" cy="11.5" r="10.75"/>
|
||||
<g><path d="M2.4,70.5c0,6.1,4.9,11,11,11H76c6.1,0,11-4.9,11-11V59.6c3.7-0.7,6.6-3.9,6.6-7.9v-7.5c0-3.9-2.8-7.2-6.6-7.9V25.5 c0-6.1-4.9-11-11-11H13.4c-6.1,0-11,4.9-11,11V70.5z M87.6,51.8c0,1.1-0.9,2-2,2H72.2c-2.8,0-5-2.2-5-5v-1.5c0-2.8,2.2-5,5-5h13.3 c1.1,0,2,0.9,2,2V51.8z M8.4,25.5c0-2.8,2.2-5,5-5H76c2.8,0,5,2.2,5,5v10.7h-8.7c-6.1,0-11,4.9-11,11v1.5c0,6.1,4.9,11,11,11H81 v10.7c0,2.8-2.2,5-5,5H13.4c-2.8,0-5-2.2-5-5V25.5z"></path></g></svg>
|
After Width: | Height: | Size: 755 B |
16
interface/resources/icons/tablet-icons/wallet-i-msg.svg
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 96 96" style="enable-background:new 0 0 96 96;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
.st1{fill:#EF3B4E;}
|
||||
</style>
|
||||
<circle class="st1" cx="84.6" cy="11.5" r="10.75"/>
|
||||
<g>
|
||||
<path class="st0" d="M2.4,70.5c0,6.1,4.9,11,11,11H76c6.1,0,11-4.9,11-11V59.6c3.7-0.7,6.6-3.9,6.6-7.9v-7.5c0-3.9-2.8-7.2-6.6-7.9
|
||||
V25.5c0-6.1-4.9-11-11-11H13.4c-6.1,0-11,4.9-11,11C2.4,25.5,2.4,70.5,2.4,70.5z M87.6,51.8c0,1.1-0.9,2-2,2H72.2c-2.8,0-5-2.2-5-5
|
||||
v-1.5c0-2.8,2.2-5,5-5h13.3c1.1,0,2,0.9,2,2L87.6,51.8L87.6,51.8z M8.4,25.5c0-2.8,2.2-5,5-5H76c2.8,0,5,2.2,5,5v10.7h-8.7
|
||||
c-6.1,0-11,4.9-11,11v1.5c0,6.1,4.9,11,11,11H81v10.7c0,2.8-2.2,5-5,5H13.4c-2.8,0-5-2.2-5-5V25.5z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 984 B |
5
interface/resources/images/eyeClosed.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="31" height="23" viewBox="0 0 31 23" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.59534 11.0156C6.16042 13.4128 9.65987 15.5898 13.6042 16.1774C17.686 16.7856 22.4164 15.7196 27.3057 11.0659C22.0721 6.07309 17.0642 5.14115 12.9153 5.90073C8.99427 6.61859 5.69298 8.87688 3.59534 11.0156ZM12.455 3.27591C17.7727 2.30235 23.9836 3.74895 30.1053 10.1333L31 11.0664L30.1053 11.9994C24.3636 17.9875 18.4774 19.5983 13.2276 18.8161C8.06048 18.0463 3.70384 14.9892 0.837069 11.9994L0 11.1265L0.778477 10.1986C3.05338 7.48717 7.2318 4.23217 12.455 3.27591Z" fill="#3D3D3D"/>
|
||||
<ellipse cx="15.6539" cy="10.9218" rx="3.65386" ry="3.81061" fill="#3D3D3D"/>
|
||||
<line x1="25" y1="2.12132" x2="7.12132" y2="20" stroke="#3D3D3D" stroke-width="3" stroke-linecap="round"/>
|
||||
</svg>
|
After Width: | Height: | Size: 825 B |
4
interface/resources/images/eyeOpen.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="31" height="16" viewBox="0 0 31 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.59534 8.01564C6.16042 10.4128 9.65987 12.5898 13.6042 13.1774C17.686 13.7856 22.4164 12.7196 27.3057 8.06585C22.0721 3.07309 17.0642 2.14115 12.9153 2.90073C8.99427 3.61859 5.69298 5.87688 3.59534 8.01564ZM12.455 0.275915C17.7727 -0.697651 23.9836 0.748949 30.1053 7.13329L31 8.06636L30.1053 8.99944C24.3636 14.9875 18.4774 16.5983 13.2276 15.8161C8.06048 15.0463 3.70384 11.9892 0.837069 8.99944L0 8.12646L0.778477 7.1986C3.05338 4.48717 7.2318 1.23217 12.455 0.275915Z" fill="#3D3D3D"/>
|
||||
<ellipse cx="15.644" cy="7.92179" rx="3.65386" ry="3.81061" fill="#3D3D3D"/>
|
||||
</svg>
|
After Width: | Height: | Size: 721 B |
BIN
interface/resources/images/interstitialPage/goTo_button.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
interface/resources/images/loadingBar_placard.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
interface/resources/images/loadingBar_progress.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_auth.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_auth.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_protocol.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_timeout.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_timeout.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
interface/resources/meshes/redirect/oopsDialog_vague.fbx
Normal file
BIN
interface/resources/meshes/redirect/oopsDialog_vague.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
@ -264,20 +264,27 @@ Item {
|
||||
StatText {
|
||||
text: "GPU: " + root.gpuFrameTime.toFixed(1) + " ms"
|
||||
}
|
||||
StatText {
|
||||
text: "Drawcalls: " + root.drawcalls
|
||||
}
|
||||
StatText {
|
||||
text: "Triangles: " + root.triangles +
|
||||
" / Material Switches: " + root.materialSwitches
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "GPU Free Memory: " + root.gpuFreeMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "GPU Textures: ";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Count: " + root.gpuTextures;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Pressure State: " + root.gpuTextureMemoryPressureState;
|
||||
}
|
||||
StatText {
|
||||
@ -287,27 +294,35 @@ Item {
|
||||
text: " " + root.gpuTextureResourceMemory + " / " + root.gpuTextureResourcePopulatedMemory + " / " + root.texturePendingTransfers + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Resident Memory: " + root.gpuTextureResidentMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Framebuffer Memory: " + root.gpuTextureFramebufferMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " External Memory: " + root.gpuTextureExternalMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "GPU Buffers: "
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Count: " + root.gpuBuffers;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Memory: " + root.gpuBufferMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "GL Swapchain Memory: " + root.glContextSwapchainMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "QML Texture Memory: " + root.qmlTextureMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
|
165
interface/resources/qml/AnimStats.qml
Normal file
@ -0,0 +1,165 @@
|
||||
import Hifi 1.0 as Hifi
|
||||
import QtQuick 2.3
|
||||
import '.'
|
||||
|
||||
Item {
|
||||
id: animStats
|
||||
|
||||
anchors.leftMargin: 300
|
||||
objectName: "StatsItem"
|
||||
property int modality: Qt.NonModal
|
||||
implicitHeight: row.height
|
||||
implicitWidth: row.width
|
||||
|
||||
Component.onCompleted: {
|
||||
animStats.parentChanged.connect(fill);
|
||||
fill();
|
||||
}
|
||||
Component.onDestruction: {
|
||||
animStats.parentChanged.disconnect(fill);
|
||||
}
|
||||
|
||||
function fill() {
|
||||
// This will cause a warning at shutdown, need to find another way to remove
|
||||
// the warning other than filling the anchors to the parent
|
||||
anchors.horizontalCenter = parent.horizontalCenter
|
||||
}
|
||||
|
||||
Hifi.AnimStats {
|
||||
id: root
|
||||
objectName: "AnimStats"
|
||||
implicitHeight: row.height
|
||||
implicitWidth: row.width
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
readonly property string bgColor: "#AA111111"
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: 8
|
||||
|
||||
Rectangle {
|
||||
width: firstCol.width + 8;
|
||||
height: firstCol.height + 8;
|
||||
color: root.bgColor;
|
||||
|
||||
Column {
|
||||
id: firstCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
|
||||
StatText {
|
||||
text: root.positionText
|
||||
}
|
||||
StatText {
|
||||
text: "Anim Vars:--------------------------------------------------------------------------------"
|
||||
}
|
||||
ListView {
|
||||
width: secondCol.width
|
||||
height: root.animVars.length * 15
|
||||
visible: root.animVars.length > 0;
|
||||
model: root.animVars
|
||||
delegate: StatText {
|
||||
text: {
|
||||
var actualText = modelData.split("|")[1];
|
||||
if (actualText) {
|
||||
return actualText;
|
||||
} else {
|
||||
return modelData;
|
||||
}
|
||||
}
|
||||
color: {
|
||||
var grayScale = parseFloat(modelData.split("|")[0]);
|
||||
return Qt.rgba(1.0, 1.0, 1.0, grayScale);
|
||||
}
|
||||
styleColor: {
|
||||
var grayScale = parseFloat(modelData.split("|")[0]);
|
||||
return Qt.rgba(0.0, 0.0, 0.0, grayScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: secondCol.width + 8
|
||||
height: secondCol.height + 8
|
||||
color: root.bgColor;
|
||||
|
||||
Column {
|
||||
id: secondCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
|
||||
StatText {
|
||||
text: root.rotationText
|
||||
}
|
||||
StatText {
|
||||
text: "State Machines:---------------------------------------------------------------------------"
|
||||
}
|
||||
ListView {
|
||||
width: firstCol.width
|
||||
height: root.animStateMachines.length * 15
|
||||
visible: root.animStateMachines.length > 0;
|
||||
model: root.animStateMachines
|
||||
delegate: StatText {
|
||||
text: {
|
||||
return modelData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: thirdCol.width + 8
|
||||
height: thirdCol.height + 8
|
||||
color: root.bgColor;
|
||||
|
||||
Column {
|
||||
id: thirdCol
|
||||
spacing: 4; x: 4; y: 4;
|
||||
|
||||
StatText {
|
||||
text: root.velocityText
|
||||
}
|
||||
StatText {
|
||||
text: "Alpha Values:--------------------------------------------------------------------------"
|
||||
}
|
||||
ListView {
|
||||
width: thirdCol.width
|
||||
height: root.animAlphaValues.length * 15
|
||||
visible: root.animAlphaValues.length > 0;
|
||||
model: root.animAlphaValues
|
||||
delegate: StatText {
|
||||
text: {
|
||||
var actualText = modelData.split("|")[1];
|
||||
if (actualText) {
|
||||
return actualText;
|
||||
} else {
|
||||
return modelData;
|
||||
}
|
||||
}
|
||||
color: {
|
||||
var grayScale = parseFloat(modelData.split("|")[0]);
|
||||
return Qt.rgba(1.0, 1.0, 1.0, grayScale);
|
||||
}
|
||||
styleColor: {
|
||||
var grayScale = parseFloat(modelData.split("|")[0]);
|
||||
return Qt.rgba(0.0, 0.0, 0.0, grayScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.parent
|
||||
onWidthChanged: {
|
||||
root.x = root.parent.width - root.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -146,7 +146,8 @@ Windows.Window {
|
||||
Qt.WindowCloseButtonHint |
|
||||
Qt.WindowMaximizeButtonHint |
|
||||
Qt.WindowMinimizeButtonHint;
|
||||
if ((flags & Desktop.ALWAYS_ON_TOP) === Desktop.ALWAYS_ON_TOP) {
|
||||
// only use the always on top feature for non Windows OS
|
||||
if (Qt.platform.os !== "windows" && (flags & Desktop.ALWAYS_ON_TOP)) {
|
||||
nativeWindowFlags |= Qt.WindowStaysOnTopHint;
|
||||
}
|
||||
nativeWindow.flags = nativeWindowFlags;
|
||||
|
@ -23,6 +23,7 @@ ModalWindow {
|
||||
objectName: "LoginDialog"
|
||||
implicitWidth: 520
|
||||
implicitHeight: 320
|
||||
closeButtonVisible: true
|
||||
destroyOnCloseButton: true
|
||||
destroyOnHidden: true
|
||||
visible: true
|
||||
|
@ -117,27 +117,27 @@ Item {
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.y / 2
|
||||
|
||||
TextField {
|
||||
id: usernameField
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 1080
|
||||
placeholderText: qsTr("Username or Email")
|
||||
TextField {
|
||||
id: usernameField
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 1080
|
||||
placeholderText: qsTr("Username or Email")
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: passwordField
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 1080
|
||||
|
||||
placeholderText: qsTr("Password")
|
||||
echoMode: TextInput.Password
|
||||
|
||||
Keys.onReturnPressed: linkAccountBody.login()
|
||||
TextField {
|
||||
id: passwordField
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
width: 1080
|
||||
|
||||
placeholderText: qsTr("Password")
|
||||
echoMode: TextInput.Password
|
||||
|
||||
Keys.onReturnPressed: linkAccountBody.login()
|
||||
}
|
||||
}
|
||||
|
||||
InfoItem {
|
||||
@ -176,7 +176,7 @@ Item {
|
||||
anchors {
|
||||
left: parent.left
|
||||
top: form.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||
}
|
||||
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
@ -201,7 +201,7 @@ Item {
|
||||
anchors {
|
||||
right: parent.right
|
||||
top: form.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||
topMargin: hifi.dimensions.contentSpacing.y / 2
|
||||
}
|
||||
spacing: hifi.dimensions.contentSpacing.x
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
@ -15,7 +15,6 @@ import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||
|
||||
import "../controls-uit"
|
||||
import "../styles-uit"
|
||||
|
||||
Item {
|
||||
id: linkAccountBody
|
||||
clip: true
|
||||
@ -24,6 +23,7 @@ Item {
|
||||
property bool failAfterSignUp: false
|
||||
|
||||
function login() {
|
||||
flavorText.visible = false
|
||||
mainTextContainer.visible = false
|
||||
toggleLoading(true)
|
||||
loginDialog.login(usernameField.text, passwordField.text)
|
||||
@ -44,7 +44,7 @@ Item {
|
||||
|
||||
function resize() {
|
||||
var targetWidth = Math.max(titleWidth, form.contentWidth);
|
||||
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
|
||||
var targetHeight = hifi.dimensions.contentSpacing.y + flavorText.height + mainTextContainer.height +
|
||||
4 * hifi.dimensions.contentSpacing.y + form.height;
|
||||
|
||||
if (additionalInformation.visible) {
|
||||
@ -88,7 +88,7 @@ Item {
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: mainTextContainer
|
||||
id: flavorText
|
||||
anchors {
|
||||
top: parent.top
|
||||
left: parent.left
|
||||
@ -96,9 +96,26 @@ Item {
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
visible: false
|
||||
text: qsTr("Sign in to High Fidelity to make friends, get HFC, and buy interesting things on the Marketplace!")
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
lineHeight: 1
|
||||
lineHeightMode: Text.ProportionalHeight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
ShortcutText {
|
||||
id: mainTextContainer
|
||||
anchors {
|
||||
top: flavorText.bottom
|
||||
left: parent.left
|
||||
margins: 0
|
||||
topMargin: 1.5 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
|
||||
visible: false
|
||||
text: qsTr("Username or password incorrect.")
|
||||
height: flavorText.height - 20
|
||||
wrapMode: Text.WordWrap
|
||||
color: hifi.colors.redAccent
|
||||
lineHeight: 1
|
||||
@ -113,26 +130,26 @@ Item {
|
||||
|
||||
anchors {
|
||||
top: mainTextContainer.bottom
|
||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||
topMargin: 1.5 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
||||
|
||||
|
||||
TextField {
|
||||
id: usernameField
|
||||
text: Settings.getValue("wallet/savedUsername", "");
|
||||
width: parent.width
|
||||
focus: true
|
||||
label: "Username or Email"
|
||||
placeholderText: "Username or Email"
|
||||
activeFocusOnPress: true
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
ShortcutText {
|
||||
z: 10
|
||||
y: usernameField.height
|
||||
anchors {
|
||||
left: usernameField.left
|
||||
top: usernameField.top
|
||||
leftMargin: usernameField.textFieldLabel.contentWidth + 10
|
||||
topMargin: -19
|
||||
right: usernameField.right
|
||||
top: usernameField.bottom
|
||||
topMargin: 4
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
||||
@ -143,26 +160,32 @@ Item {
|
||||
|
||||
onLinkActivated: loginDialog.openUrl(link)
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
root.text = "";
|
||||
}
|
||||
Component.onCompleted: {
|
||||
var savedUsername = Settings.getValue("wallet/savedUsername", "");
|
||||
usernameField.text = savedUsername === "Unknown user" ? "" : savedUsername;
|
||||
}
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: passwordField
|
||||
width: parent.width
|
||||
|
||||
label: "Password"
|
||||
echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
|
||||
placeholderText: "Password"
|
||||
activeFocusOnPress: true
|
||||
echoMode: passwordFieldMouseArea.showPassword ? TextInput.Normal : TextInput.Password
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
|
||||
ShortcutText {
|
||||
id: forgotPasswordShortcut
|
||||
y: passwordField.height
|
||||
z: 10
|
||||
anchors {
|
||||
left: passwordField.left
|
||||
top: passwordField.top
|
||||
leftMargin: passwordField.textFieldLabel.contentWidth + 10
|
||||
topMargin: -19
|
||||
right: passwordField.right
|
||||
top: passwordField.bottom
|
||||
topMargin: 4
|
||||
}
|
||||
|
||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
||||
@ -179,12 +202,44 @@ Item {
|
||||
root.isPassword = true;
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: linkAccountBody.login()
|
||||
}
|
||||
Rectangle {
|
||||
id: showPasswordHitbox
|
||||
z: 10
|
||||
x: passwordField.width - ((passwordField.height) * 31 / 23)
|
||||
width: parent.width - (parent.width - (parent.height * 31/16))
|
||||
height: parent.height
|
||||
anchors {
|
||||
right: parent.right
|
||||
}
|
||||
color: "transparent"
|
||||
|
||||
CheckBox {
|
||||
id: showPassword
|
||||
text: "Show password"
|
||||
Image {
|
||||
id: showPasswordImage
|
||||
width: passwordField.height * 16 / 23
|
||||
height: passwordField.height * 16 / 23
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: 8
|
||||
top: parent.top
|
||||
topMargin: passwordFieldMouseArea.showPassword ? 6 : 8
|
||||
bottom: parent.bottom
|
||||
bottomMargin: passwordFieldMouseArea.showPassword ? 5 : 8
|
||||
}
|
||||
source: passwordFieldMouseArea.showPassword ? "../../images/eyeClosed.svg" : "../../images/eyeOpen.svg"
|
||||
MouseArea {
|
||||
id: passwordFieldMouseArea
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton
|
||||
property bool showPassword: false
|
||||
onClicked: {
|
||||
showPassword = !showPassword;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: linkAccountBody.login()
|
||||
}
|
||||
|
||||
InfoItem {
|
||||
@ -206,22 +261,36 @@ Item {
|
||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
CheckBox {
|
||||
id: autoLogoutCheckbox
|
||||
checked: !Settings.getValue("wallet/autoLogout", true)
|
||||
text: "Keep me signed in"
|
||||
boxSize: 20;
|
||||
labelFontSize: 15
|
||||
color: hifi.colors.black
|
||||
onCheckedChanged: {
|
||||
Settings.setValue("wallet/autoLogout", !checked);
|
||||
if (checked) {
|
||||
Settings.setValue("wallet/savedUsername", Account.username);
|
||||
} else {
|
||||
Settings.setValue("wallet/savedUsername", "");
|
||||
}
|
||||
}
|
||||
Component.onDestruction: {
|
||||
Settings.setValue("wallet/autoLogout", !checked);
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: linkAccountButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 200
|
||||
|
||||
text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login")
|
||||
text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Log in")
|
||||
color: hifi.buttons.blue
|
||||
|
||||
onClicked: linkAccountBody.login()
|
||||
}
|
||||
|
||||
Button {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Cancel")
|
||||
onClicked: root.tryDestroy()
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
@ -234,7 +303,7 @@ Item {
|
||||
RalewaySemiBold {
|
||||
size: hifi.fontSizes.inputLabel
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: qsTr("Don't have an account?")
|
||||
text: qsTr("New to High Fidelity?")
|
||||
}
|
||||
|
||||
Button {
|
||||
@ -269,6 +338,7 @@ Item {
|
||||
|
||||
if (failAfterSignUp) {
|
||||
mainTextContainer.text = "Account created successfully."
|
||||
flavorText.visible = true
|
||||
mainTextContainer.visible = true
|
||||
}
|
||||
|
||||
@ -279,7 +349,15 @@ Item {
|
||||
target: loginDialog
|
||||
onHandleLoginCompleted: {
|
||||
console.log("Login Succeeded, linking steam account")
|
||||
|
||||
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
|
||||
if (poppedUp) {
|
||||
console.log("[ENCOURAGELOGINDIALOG]: logging in")
|
||||
var data = {
|
||||
"action": "user logged in"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
Settings.setValue("loginDialogPoppedUp", false);
|
||||
}
|
||||
if (loginDialog.isSteamRunning()) {
|
||||
loginDialog.linkSteam()
|
||||
} else {
|
||||
@ -290,6 +368,16 @@ Item {
|
||||
}
|
||||
onHandleLoginFailed: {
|
||||
console.log("Login Failed")
|
||||
var poppedUp = Settings.getValue("loginDialogPoppedUp", false);
|
||||
if (poppedUp) {
|
||||
console.log("[ENCOURAGELOGINDIALOG]: failed logging in")
|
||||
var data = {
|
||||
"action": "user failed logging in"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
Settings.setValue("loginDialogPoppedUp", false);
|
||||
}
|
||||
flavorText.visible = true
|
||||
mainTextContainer.visible = true
|
||||
toggleLoading(false)
|
||||
}
|
||||
|
@ -192,21 +192,6 @@ Item {
|
||||
StatText {
|
||||
text: "Yaw: " + root.yaw.toFixed(1)
|
||||
}
|
||||
StatText {
|
||||
visible: root.animStackNames.length > 0;
|
||||
text: "Anim Stack Names:"
|
||||
}
|
||||
ListView {
|
||||
width: geoCol.width
|
||||
height: root.animStackNames.length * 15
|
||||
visible: root.animStackNames.length > 0;
|
||||
model: root.animStackNames
|
||||
delegate: StatText {
|
||||
text: modelData.length > 30
|
||||
? modelData.substring(0, 5) + "..." + modelData.substring(modelData.length - 22)
|
||||
: modelData
|
||||
}
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "Avatar Mixer In: " + root.avatarMixerInKbps + " kbps, " +
|
||||
@ -304,52 +289,69 @@ Item {
|
||||
StatText {
|
||||
text: "GPU frame size: " + root.gpuFrameSize.x + " x " + root.gpuFrameSize.y
|
||||
}
|
||||
StatText {
|
||||
text: "Drawcalls: " + root.drawcalls
|
||||
}
|
||||
StatText {
|
||||
text: "Triangles: " + root.triangles +
|
||||
" / Material Switches: " + root.materialSwitches
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "GPU Free Memory: " + root.gpuFreeMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "GPU Textures: ";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Count: " + root.gpuTextures;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Pressure State: " + root.gpuTextureMemoryPressureState;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
property bool showIdeal: (root.gpuTextureResourceIdealMemory != root.gpuTextureResourceMemory);
|
||||
text: " Resource Allocated " + (showIdeal ? "(Ideal)" : "") + " / Populated / Pending: ";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
property bool showIdeal: (root.gpuTextureResourceIdealMemory != root.gpuTextureResourceMemory);
|
||||
text: " " + root.gpuTextureResourceMemory + (showIdeal ? ("(" + root.gpuTextureResourceIdealMemory + ")") : "") + " / " + root.gpuTextureResourcePopulatedMemory + " / " + root.texturePendingTransfers + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Resident Memory: " + root.gpuTextureResidentMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Framebuffer Memory: " + root.gpuTextureFramebufferMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " External Memory: " + root.gpuTextureExternalMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "GPU Buffers: "
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Count: " + root.gpuBuffers;
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: " Memory: " + root.gpuBufferMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "GL Swapchain Memory: " + root.glContextSwapchainMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
visible: root.expanded;
|
||||
text: "QML Texture Memory: " + root.qmlTextureMemory + " MB";
|
||||
}
|
||||
StatText {
|
||||
|
@ -46,7 +46,7 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
property var jointNames;
|
||||
property var jointNames: []
|
||||
property var currentAvatarSettings;
|
||||
|
||||
function fetchAvatarModelName(marketId, avatar) {
|
||||
@ -175,7 +175,14 @@ Rectangle {
|
||||
displayNameInput.text = getAvatarsData.displayName;
|
||||
currentAvatarSettings = getAvatarsData.currentAvatarSettings;
|
||||
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
var bookmarkAvatarIndex = allAvatars.findAvatarIndexByValue(currentAvatar);
|
||||
if (bookmarkAvatarIndex === -1) {
|
||||
currentAvatar.name = '';
|
||||
} else {
|
||||
currentAvatar.name = allAvatars.get(bookmarkAvatarIndex).name;
|
||||
allAvatars.move(bookmarkAvatarIndex, 0, 1);
|
||||
}
|
||||
view.setPage(0);
|
||||
} else if (message.method === 'updateAvatarInBookmarks') {
|
||||
updateCurrentAvatarInBookmarks(currentAvatar);
|
||||
} else if (message.method === 'selectAvatarEntity') {
|
||||
|
@ -530,9 +530,7 @@ Item {
|
||||
maximumValue: 20.0
|
||||
stepSize: 5
|
||||
updateValueWhileDragging: true
|
||||
Component.onCompleted: {
|
||||
value = Users.getAvatarGain(uuid);
|
||||
}
|
||||
value: Users.getAvatarGain(uuid)
|
||||
onValueChanged: {
|
||||
updateGainFromQML(uuid, value, false);
|
||||
}
|
||||
|
@ -271,6 +271,8 @@ Rectangle {
|
||||
connectionsUserModel.getFirstPage();
|
||||
}
|
||||
activeTab = "connectionsTab";
|
||||
connectionsOnlineDot.visible = false;
|
||||
pal.sendToScript({method: 'hideNotificationDot'});
|
||||
connectionsHelpText.color = hifi.colors.blueAccent;
|
||||
}
|
||||
}
|
||||
@ -298,6 +300,16 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
id: connectionsOnlineDot;
|
||||
visible: false;
|
||||
width: 10;
|
||||
height: width;
|
||||
radius: width;
|
||||
color: "#EF3B4E"
|
||||
anchors.left: parent.left;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
}
|
||||
// "CONNECTIONS" text
|
||||
RalewaySemiBold {
|
||||
id: connectionsTabSelectorText;
|
||||
@ -305,7 +317,11 @@ Rectangle {
|
||||
// Text size
|
||||
size: hifi.fontSizes.tabularData;
|
||||
// Anchors
|
||||
anchors.fill: parent;
|
||||
anchors.left: connectionsOnlineDot.visible ? connectionsOnlineDot.right : parent.left;
|
||||
anchors.leftMargin: connectionsOnlineDot.visible ? 4 : 0;
|
||||
anchors.top: parent.top;
|
||||
anchors.bottom: parent.bottom;
|
||||
anchors.right: parent.right;
|
||||
// Style
|
||||
font.capitalization: Font.AllUppercase;
|
||||
color: activeTab === "connectionsTab" ? hifi.colors.blueAccent : hifi.colors.baseGray;
|
||||
@ -326,7 +342,7 @@ Rectangle {
|
||||
anchors.left: connectionsTabSelectorTextContainer.left;
|
||||
anchors.top: connectionsTabSelectorTextContainer.top;
|
||||
anchors.topMargin: 1;
|
||||
anchors.leftMargin: connectionsTabSelectorTextMetrics.width + 42;
|
||||
anchors.leftMargin: connectionsTabSelectorTextMetrics.width + 42 + connectionsOnlineDot.width + connectionsTabSelectorText.anchors.leftMargin;
|
||||
RalewayRegular {
|
||||
id: connectionsHelpText;
|
||||
text: "[?]";
|
||||
@ -780,6 +796,12 @@ Rectangle {
|
||||
headerVisible: true;
|
||||
sortIndicatorColumn: settings.connectionsSortIndicatorColumn;
|
||||
sortIndicatorOrder: settings.connectionsSortIndicatorOrder;
|
||||
onSortIndicatorColumnChanged: {
|
||||
settings.connectionsSortIndicatorColumn = sortIndicatorColumn;
|
||||
}
|
||||
onSortIndicatorOrderChanged: {
|
||||
settings.connectionsSortIndicatorOrder = sortIndicatorOrder;
|
||||
}
|
||||
|
||||
TableViewColumn {
|
||||
id: connectionsUserNameHeader;
|
||||
@ -1261,6 +1283,9 @@ Rectangle {
|
||||
case 'http.response':
|
||||
http.handleHttpResponse(message);
|
||||
break;
|
||||
case 'changeConnectionsDotStatus':
|
||||
connectionsOnlineDot.visible = message.shouldShowDot;
|
||||
break;
|
||||
default:
|
||||
console.log('Unrecognized message:', JSON.stringify(message));
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ Rectangle {
|
||||
HifiConstants { id: hifi; }
|
||||
|
||||
property var eventBridge;
|
||||
property string title: "Audio Settings - " + AudioScriptingInterface.context;
|
||||
property string title: "Audio Settings"
|
||||
signal sendToScript(var message);
|
||||
|
||||
color: hifi.colors.baseGray;
|
||||
|
@ -25,7 +25,17 @@ Rectangle {
|
||||
modified = false;
|
||||
}
|
||||
|
||||
property var jointNames;
|
||||
property var jointNames: []
|
||||
onJointNamesChanged: {
|
||||
jointsModel.clear();
|
||||
for (var i = 0; i < jointNames.length; ++i) {
|
||||
var jointName = jointNames[i];
|
||||
if (jointName !== 'LeftHand' && jointName !== 'RightHand') {
|
||||
jointsModel.append({'text' : jointName, 'jointIndex' : i});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property string avatarName: ''
|
||||
property var wearablesModel;
|
||||
|
||||
@ -268,20 +278,30 @@ Rectangle {
|
||||
anchors.right: parent.right
|
||||
enabled: getCurrentWearable() !== null && !isSoft.checked
|
||||
comboBox.displayText: isSoft.checked ? 'Hips' : comboBox.currentText
|
||||
comboBox.textRole: "text"
|
||||
|
||||
model: jointNames
|
||||
model: ListModel {
|
||||
id: jointsModel
|
||||
}
|
||||
property bool notify: false
|
||||
|
||||
function set(jointIndex) {
|
||||
notify = false;
|
||||
currentIndex = jointIndex;
|
||||
for (var i = 0; i < jointsModel.count; ++i) {
|
||||
if (jointsModel.get(i).jointIndex === jointIndex) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
notify = true;
|
||||
}
|
||||
|
||||
function notifyJointChanged() {
|
||||
modified = true;
|
||||
var jointIndex = jointsModel.get(jointsCombobox.currentIndex).jointIndex;
|
||||
|
||||
var properties = {
|
||||
parentJointIndex: currentIndex,
|
||||
parentJointIndex: jointIndex,
|
||||
localPosition: {
|
||||
x: positionVector.xvalue,
|
||||
y: positionVector.yvalue,
|
||||
|
@ -24,6 +24,7 @@ Item {
|
||||
|
||||
fragmentShader: {
|
||||
"
|
||||
#version 150 core
|
||||
varying highp vec2 qt_TexCoord0;
|
||||
uniform lowp sampler2D source;
|
||||
uniform lowp sampler2D mask;
|
||||
|
@ -552,6 +552,10 @@ Rectangle {
|
||||
// Alignment
|
||||
horizontalAlignment: Text.AlignLeft;
|
||||
verticalAlignment: Text.AlignVCenter;
|
||||
onLinkActivated: {
|
||||
// Only case is to go to the bank.
|
||||
sendToScript({method: 'gotoBank'});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1107,25 +1111,32 @@ Rectangle {
|
||||
}
|
||||
|
||||
function handleBuyAgainLogic() {
|
||||
// If you can buy this item again...
|
||||
if (canBuyAgain()) {
|
||||
// If you can't afford another copy of the item...
|
||||
if (root.balanceAfterPurchase < 0) {
|
||||
// If you already own the item...
|
||||
if (root.alreadyOwned) {
|
||||
buyText.text = "<b>Your Wallet does not have sufficient funds to purchase this item again.</b>";
|
||||
// Else if you don't already own the item...
|
||||
} else {
|
||||
buyText.text = "<b>Your Wallet does not have sufficient funds to purchase this item.</b>";
|
||||
}
|
||||
buyTextContainer.color = "#FFC3CD";
|
||||
buyTextContainer.border.color = "#F3808F";
|
||||
buyGlyph.text = hifi.glyphs.alert;
|
||||
buyGlyph.size = 54;
|
||||
// If you CAN afford another copy of the item...
|
||||
// General rules, implemented in various scattered places in this file:
|
||||
// 1. If you already own the item, a viewInMyPurchasesButton is visible,
|
||||
// and the buyButton is visible (and says "Buy it again") ONLY if it is a type you canBuyAgain.
|
||||
// 2. Separately,
|
||||
// a. If you don't have enough money to buy, the buyText becomes visible and tells you, and the buyButton is disabled.
|
||||
// b. Otherwise, if the item is a content set and you don't have rez permission, the buyText becomes visible and tells you so.
|
||||
|
||||
// If you can't afford another copy of the item...
|
||||
if (root.balanceAfterPurchase < 0) {
|
||||
// If you already own the item...
|
||||
if (!root.alreadyOwned) {
|
||||
buyText.text = "<b>Your Wallet does not have sufficient funds to purchase this item.</b>";
|
||||
// Else if you don't already own the item...
|
||||
} else if (canBuyAgain()) {
|
||||
buyText.text = "<b>Your Wallet does not have sufficient funds to purchase this item again.</b>";
|
||||
} else {
|
||||
handleContentSets();
|
||||
buyText.text = "<b>While you do not have sufficient funds to buy this, you already have this item.</b>"
|
||||
}
|
||||
buyText.text += " Visit <a href='#'>Bank of High Fidelity</a> to get more HFC."
|
||||
buyTextContainer.color = "#FFC3CD";
|
||||
buyTextContainer.border.color = "#F3808F";
|
||||
buyGlyph.text = hifi.glyphs.alert;
|
||||
buyGlyph.size = 54;
|
||||
// If you CAN afford another copy of the item...
|
||||
} else {
|
||||
handleContentSets();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,290 @@
|
||||
//
|
||||
// marketplaceItemTester
|
||||
// qml/hifi/commerce/marketplaceItemTester
|
||||
//
|
||||
// Load items not in the marketplace for testing purposes
|
||||
//
|
||||
// Created by Zach Fox on 2018-09-05
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import QtQuick 2.5
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Dialogs 1.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import Hifi 1.0 as Hifi
|
||||
import "../../../styles-uit" as HifiStylesUit
|
||||
import "../../../controls-uit" as HifiControlsUit
|
||||
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string installedApps
|
||||
property var nextResourceObjectId: 0
|
||||
signal sendToScript(var message)
|
||||
|
||||
HifiStylesUit.HifiConstants { id: hifi }
|
||||
ListModel { id: resourceListModel }
|
||||
|
||||
color: hifi.colors.white
|
||||
|
||||
AnimatedImage {
|
||||
id: spinner;
|
||||
source: "spinner.gif"
|
||||
width: 74;
|
||||
height: width;
|
||||
anchors.verticalCenter: parent.verticalCenter;
|
||||
anchors.horizontalCenter: parent.horizontalCenter;
|
||||
}
|
||||
|
||||
function fromScript(message) {
|
||||
switch (message.method) {
|
||||
case "newResourceObjectInTest":
|
||||
var resourceObject = message.resourceObject;
|
||||
resourceListModel.append(resourceObject);
|
||||
spinner.visible = false;
|
||||
break;
|
||||
case "nextObjectIdInTest":
|
||||
nextResourceObjectId = message.id;
|
||||
spinner.visible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function buildResourceObj(resource) {
|
||||
resource = resource.trim();
|
||||
var assetType = (resource.match(/\.app\.json$/) ? "application" :
|
||||
resource.match(/\.fst$/) ? "avatar" :
|
||||
resource.match(/\.json\.gz$/) ? "content set" :
|
||||
resource.match(/\.json$/) ? "entity or wearable" :
|
||||
"unknown");
|
||||
return { "id": nextResourceObjectId++,
|
||||
"resource": resource,
|
||||
"assetType": assetType };
|
||||
}
|
||||
|
||||
function installResourceObj(resourceObj) {
|
||||
if ("application" === resourceObj.assetType) {
|
||||
Commerce.installApp(resourceObj.resource);
|
||||
}
|
||||
}
|
||||
|
||||
function addAllInstalledAppsToList() {
|
||||
var i, apps = Commerce.getInstalledApps().split(","), len = apps.length;
|
||||
for(i = 0; i < len - 1; ++i) {
|
||||
if (i in apps) {
|
||||
resourceListModel.append(buildResourceObj(apps[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toUrl(resource) {
|
||||
var httpPattern = /^http/i;
|
||||
return httpPattern.test(resource) ? resource : "file:///" + resource;
|
||||
}
|
||||
|
||||
function rezEntity(resource, entityType) {
|
||||
sendToScript({
|
||||
method: 'tester_rezClicked',
|
||||
itemHref: toUrl(resource),
|
||||
itemType: entityType});
|
||||
}
|
||||
|
||||
ListView {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 12
|
||||
anchors.bottomMargin: 40
|
||||
anchors.rightMargin: 12
|
||||
model: resourceListModel
|
||||
spacing: 5
|
||||
interactive: false
|
||||
|
||||
delegate: RowLayout {
|
||||
anchors.left: parent.left
|
||||
width: parent.width
|
||||
spacing: 5
|
||||
|
||||
property var actions: {
|
||||
"forward": function(resource, assetType){
|
||||
switch(assetType) {
|
||||
case "application":
|
||||
Commerce.openApp(resource);
|
||||
break;
|
||||
case "avatar":
|
||||
MyAvatar.useFullAvatarURL(resource);
|
||||
break;
|
||||
case "content set":
|
||||
urlHandler.handleUrl("hifi://localhost/0,0,0");
|
||||
Commerce.replaceContentSet(toUrl(resource), "");
|
||||
break;
|
||||
case "entity":
|
||||
case "wearable":
|
||||
rezEntity(resource, assetType);
|
||||
break;
|
||||
default:
|
||||
print("Marketplace item tester unsupported assetType " + assetType);
|
||||
}
|
||||
},
|
||||
"trash": function(resource, assetType){
|
||||
if ("application" === assetType) {
|
||||
Commerce.uninstallApp(resource);
|
||||
}
|
||||
sendToScript({
|
||||
method: "tester_deleteResourceObject",
|
||||
objectId: resourceListModel.get(index).id});
|
||||
resourceListModel.remove(index);
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
Layout.preferredWidth: root.width * .6
|
||||
spacing: 5
|
||||
Text {
|
||||
text: {
|
||||
var match = resource.match(/\/([^/]*)$/);
|
||||
return match ? match[1] : resource;
|
||||
}
|
||||
font.pointSize: 12
|
||||
horizontalAlignment: Text.AlignBottom
|
||||
}
|
||||
Text {
|
||||
text: resource
|
||||
font.pointSize: 8
|
||||
width: root.width * .6
|
||||
horizontalAlignment: Text.AlignBottom
|
||||
wrapMode: Text.WrapAnywhere
|
||||
}
|
||||
}
|
||||
|
||||
ComboBox {
|
||||
id: comboBox
|
||||
|
||||
Layout.preferredWidth: root.width * .2
|
||||
|
||||
model: [
|
||||
"application",
|
||||
"avatar",
|
||||
"content set",
|
||||
"entity",
|
||||
"wearable",
|
||||
"unknown"
|
||||
]
|
||||
|
||||
currentIndex: (("entity or wearable" === assetType) ?
|
||||
model.indexOf("unknown") : model.indexOf(assetType))
|
||||
|
||||
Component.onCompleted: {
|
||||
onCurrentIndexChanged.connect(function() {
|
||||
assetType = model[currentIndex];
|
||||
sendToScript({
|
||||
method: "tester_updateResourceObjectAssetType",
|
||||
objectId: resourceListModel.get(index)["id"],
|
||||
assetType: assetType });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: [ "forward", "trash" ]
|
||||
|
||||
HifiStylesUit.HiFiGlyphs {
|
||||
property var glyphs: {
|
||||
"application": hifi.glyphs.install,
|
||||
"avatar": hifi.glyphs.avatar,
|
||||
"content set": hifi.glyphs.globe,
|
||||
"entity": hifi.glyphs.wand,
|
||||
"trash": hifi.glyphs.trash,
|
||||
"unknown": hifi.glyphs.circleSlash,
|
||||
"wearable": hifi.glyphs.hat,
|
||||
}
|
||||
text: (("trash" === modelData) ?
|
||||
glyphs.trash :
|
||||
glyphs[comboBox.model[comboBox.currentIndex]])
|
||||
size: ("trash" === modelData) ? 22 : 30
|
||||
color: hifi.colors.black
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
actions[modelData](resource, comboBox.currentText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
headerPositioning: ListView.OverlayHeader
|
||||
header: HifiStylesUit.RalewayRegular {
|
||||
id: rootHeader
|
||||
text: "Marketplace Item Tester"
|
||||
height: 80
|
||||
width: paintedWidth
|
||||
size: 22
|
||||
color: hifi.colors.black
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
}
|
||||
|
||||
footerPositioning: ListView.OverlayFooter
|
||||
footer: Row {
|
||||
id: rootActions
|
||||
spacing: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
property string currentAction
|
||||
property var actions: {
|
||||
"Load File": function(){
|
||||
rootActions.currentAction = "load file";
|
||||
Window.browseChanged.connect(onResourceSelected);
|
||||
Window.browseAsync("Please select a file (*.app.json *.json *.fst *.json.gz)", "", "Assets (*.app.json *.json *.fst *.json.gz)");
|
||||
},
|
||||
"Load URL": function(){
|
||||
rootActions.currentAction = "load url";
|
||||
Window.promptTextChanged.connect(onResourceSelected);
|
||||
Window.promptAsync("Please enter a URL", "");
|
||||
}
|
||||
}
|
||||
|
||||
function onResourceSelected(resource) {
|
||||
// It is possible that we received the present signal
|
||||
// from something other than our browserAsync window.
|
||||
// Alas, there is nothing we can do about that so charge
|
||||
// ahead as though we are sure the present signal is one
|
||||
// we expect.
|
||||
switch(currentAction) {
|
||||
case "load file":
|
||||
Window.browseChanged.disconnect(onResourceSelected);
|
||||
break
|
||||
case "load url":
|
||||
Window.promptTextChanged.disconnect(onResourceSelected);
|
||||
break;
|
||||
}
|
||||
if (resource) {
|
||||
var resourceObj = buildResourceObj(resource);
|
||||
installResourceObj(resourceObj);
|
||||
sendToScript({
|
||||
method: 'tester_newResourceObject',
|
||||
resourceObject: resourceObj });
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: [ "Load File", "Load URL" ]
|
||||
HifiControlsUit.Button {
|
||||
color: hifi.buttons.blue
|
||||
fontSize: 20
|
||||
text: modelData
|
||||
width: root.width / 3
|
||||
height: 40
|
||||
onClicked: actions[text]()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 45 KiB |
@ -59,7 +59,7 @@ Item {
|
||||
|
||||
Connections {
|
||||
target: Commerce;
|
||||
|
||||
|
||||
onContentSetChanged: {
|
||||
if (contentSetHref === root.itemHref) {
|
||||
showConfirmation = true;
|
||||
@ -135,7 +135,7 @@ Item {
|
||||
anchors.topMargin: 8;
|
||||
width: 30;
|
||||
height: width;
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: closeContextMenuGlyph;
|
||||
text: hifi.glyphs.close;
|
||||
@ -376,7 +376,7 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
transform: Rotation {
|
||||
id: rotation;
|
||||
origin.x: flipable.width/2;
|
||||
@ -509,7 +509,7 @@ Item {
|
||||
}
|
||||
verticalAlignment: Text.AlignTop;
|
||||
}
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: statusIcon;
|
||||
text: {
|
||||
@ -588,7 +588,7 @@ Item {
|
||||
border.width: 1;
|
||||
border.color: "#E2334D";
|
||||
}
|
||||
|
||||
|
||||
HiFiGlyphs {
|
||||
id: contextMenuGlyph;
|
||||
text: hifi.glyphs.verticalEllipsis;
|
||||
@ -615,7 +615,7 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: rezzedNotifContainer;
|
||||
z: 998;
|
||||
@ -663,13 +663,13 @@ Item {
|
||||
Tablet.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
Tablet.playSound(TabletEnums.ButtonHover);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onClicked: {
|
||||
Tablet.playSound(TabletEnums.ButtonClick);
|
||||
if (root.itemType === "contentSet") {
|
||||
@ -775,7 +775,7 @@ Item {
|
||||
// Style
|
||||
color: hifi.colors.redAccent;
|
||||
horizontalAlignment: Text.AlignRight;
|
||||
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent;
|
||||
hoverEnabled: true;
|
||||
|
@ -93,7 +93,7 @@ Rectangle {
|
||||
console.log("Failed to get Available Updates", result.data.message);
|
||||
} else {
|
||||
sendToScript({method: 'purchases_availableUpdatesReceived', numUpdates: result.data.updates.length });
|
||||
root.numUpdatesAvailable = result.data.updates.length;
|
||||
root.numUpdatesAvailable = result.total_entries;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,9 +408,7 @@ Rectangle {
|
||||
|
||||
Connections {
|
||||
onSendSignalToWallet: {
|
||||
if (msg.method === 'walletReset' || msg.method === 'passphraseReset') {
|
||||
sendToScript(msg);
|
||||
} else if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||
if (msg.method === 'walletSecurity_changeSecurityImage') {
|
||||
securityImageChange.initModel();
|
||||
root.activeView = "securityImageChange";
|
||||
}
|
||||
@ -831,6 +829,7 @@ Rectangle {
|
||||
Commerce.getWalletAuthenticatedStatus(); // before writing security image, ensures that salt/account password is set.
|
||||
Commerce.chooseSecurityImage(securityImagePath);
|
||||
Commerce.generateKeyPair();
|
||||
followReferrer({ referrer: walletSetup.referrer });
|
||||
}
|
||||
|
||||
function addLeadingZero(n) {
|
||||
@ -838,7 +837,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
function followReferrer(msg) {
|
||||
if (msg.referrer === '' || msg.referrer === 'marketplace cta') {
|
||||
if (msg.referrer === '') {
|
||||
root.activeView = "initialize";
|
||||
Commerce.getWalletStatus();
|
||||
} else if (msg.referrer === 'purchases') {
|
||||
|
@ -45,14 +45,6 @@ Item {
|
||||
onHistoryResult : {
|
||||
transactionHistoryModel.handlePage(null, result);
|
||||
}
|
||||
|
||||
onAvailableUpdatesResult: {
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get Available Updates", result.data.message);
|
||||
} else {
|
||||
sendToScript({method: 'wallet_availableUpdatesReceived', numUpdates: result.data.updates.length });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
@ -28,7 +28,7 @@ Item {
|
||||
property string activeView: "step_1";
|
||||
property string lastPage;
|
||||
property bool hasShownSecurityImageTip: false;
|
||||
property string referrer;
|
||||
property string referrer: '';
|
||||
property string keyFilePath;
|
||||
property date startingTimestamp;
|
||||
property string setupAttemptID;
|
||||
|
@ -18,6 +18,7 @@ import "../../windows"
|
||||
Rectangle {
|
||||
id: root
|
||||
objectName: "DCConectionTiming"
|
||||
property string title: "Domain Connection Timing"
|
||||
|
||||
signal sendToScript(var message);
|
||||
property bool isHMD: false
|
||||
@ -33,7 +34,7 @@ Rectangle {
|
||||
Row {
|
||||
id: header
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: hifi.dimensions.tabletMenuHeader
|
||||
anchors.topMargin: hifi.dimensions.contentMargin.y
|
||||
anchors.leftMargin: 5
|
||||
anchors.rightMargin: 5
|
||||
anchors.left: parent.left
|
||||
|
@ -18,6 +18,7 @@ import "../../windows"
|
||||
Rectangle {
|
||||
id: root
|
||||
objectName: "EntityStatistics"
|
||||
property string title: "Entity Statistics"
|
||||
|
||||
signal sendToScript(var message);
|
||||
property bool isHMD: false
|
||||
@ -40,6 +41,7 @@ Rectangle {
|
||||
id: scrollView
|
||||
width: parent.width
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: hifi.dimensions.contentMargin.y
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: hifi.dimensions.tabletMenuHeader
|
||||
contentWidth: column.implicitWidth
|
||||
@ -48,10 +50,15 @@ Rectangle {
|
||||
|
||||
Column {
|
||||
id: column
|
||||
anchors.margins: 10
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
y: hifi.dimensions.tabletMenuHeader //-bgNavBar
|
||||
anchors {
|
||||
topMargin: 0
|
||||
leftMargin: 10
|
||||
rightMargin: 10
|
||||
bottomMargin: 0
|
||||
}
|
||||
spacing: 20
|
||||
|
||||
TabletEntityStatisticsItem {
|
||||
|
@ -24,6 +24,8 @@ Item {
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
|
||||
property string title: "Controls"
|
||||
|
||||
HifiConstants { id: hifi }
|
||||
|
||||
TabBar {
|
||||
|
@ -79,7 +79,7 @@ StackView {
|
||||
return;
|
||||
}
|
||||
location.text = targetString;
|
||||
toggleOrGo(true, targetString);
|
||||
toggleOrGo(targetString, true);
|
||||
clearAddressLineTimer.start();
|
||||
}
|
||||
|
||||
@ -105,7 +105,6 @@ StackView {
|
||||
propagateComposedEvents: true
|
||||
onPressed: {
|
||||
parent.forceActiveFocus();
|
||||
addressBarDialog.keyboardEnabled = false;
|
||||
mouse.accepted = false;
|
||||
}
|
||||
}
|
||||
@ -223,7 +222,6 @@ StackView {
|
||||
updateLocationText(text.length > 0);
|
||||
}
|
||||
onAccepted: {
|
||||
addressBarDialog.keyboardEnabled = false;
|
||||
toggleOrGo();
|
||||
}
|
||||
|
||||
@ -378,7 +376,7 @@ StackView {
|
||||
|
||||
HifiControls.Keyboard {
|
||||
id: keyboard
|
||||
raised: parent.keyboardEnabled
|
||||
raised: parent.keyboardEnabled && parent.keyboardRaised
|
||||
numeric: parent.punctuationMode
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
@ -401,7 +399,7 @@ StackView {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleOrGo(fromSuggestions, address) {
|
||||
function toggleOrGo(address, fromSuggestions) {
|
||||
if (address !== undefined && address !== "") {
|
||||
addressBarDialog.loadAddress(address, fromSuggestions);
|
||||
clearAddressLineTimer.start();
|
||||
|