diff --git a/.gitignore b/.gitignore
index b29554cf..264b2908 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,5 +12,5 @@ local.properties
/app/release
/magisk*
/prebuilts
-/SettingsLibParts
+/SettingsLib
/gradlew.bat
diff --git a/README.md b/README.md
index 15f11632..093a4ba5 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@
chaldeaprjkt's GameSpace is an alternative to the Google's proprietary implementation of the Game Dashboard with a goals of providing basic user-interface for the [Android Game Mode API](https://developer.android.com/games/gamemode/gamemode-api).
Gamespace requires several patches to be applied on the AOSP's SystemUI and Settings :
-- [frameworks/base](https://github.com/chaldeaprjkt/chaldea_frameworks_base/commits/12L/gamespace)
-- [packages/apps/Settings](https://github.com/chaldeaprjkt/chaldea_packages_apps_Settings/commits/12L/gamespace)
+- [frameworks/base](https://github.com/chaldeaprjkt/chaldea_frameworks_base/commits/13/gamespace)
+- [packages/apps/Settings](https://github.com/chaldeaprjkt/chaldea_packages_apps_Settings/commits/13/gamespace)
## License
diff --git a/app/build.gradle b/app/build.gradle
index c56432e3..b977da06 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,3 +1,6 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
@@ -5,14 +8,14 @@ plugins {
}
android {
- compileSdk 31
+ compileSdk 33
defaultConfig {
applicationId "io.chaldeaprjkt.gamespace"
- minSdk 31
- targetSdk 31
- versionCode 99
- versionName "0.1-beta"
+ minSdk 33
+ targetSdk 33
+ versionCode 100
+ versionName "0.2"
}
signingConfigs {
platform {
@@ -34,54 +37,35 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
- kotlinOptions {
- jvmTarget = '1.8'
+
+ tasks.withType(KotlinCompile).configureEach {
+ compilerOptions.jvmTarget = JvmTarget.JVM_1_8
}
+
sourceSets {
main {
aidl.srcDirs = ['src/main/java']
}
}
- lintOptions {
- disable 'ContentDescription'
- disable 'QueryAllPackagesPermission'
- disable 'ProtectedPermissions'
- disable 'OldTargetApi'
- disable 'UseCompatLoadingForDrawables'
- disable 'UnsafeProtectedBroadcastReceiver'
- disable 'AppCompatCustomView'
+ lint {
+ disable 'ContentDescription', 'QueryAllPackagesPermission', 'ProtectedPermissions', 'OldTargetApi', 'UseCompatLoadingForDrawables', 'UnsafeProtectedBroadcastReceiver', 'AppCompatCustomView'
}
}
-def androidPath = "${rootDir}/../../../"
-def frameworkClassesJar = "${androidPath}/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar"
-
dependencies {
- kapt 'com.google.dagger:hilt-compiler:2.40.5'
+ compileOnly files(frameworkJar)
+ implementation project(path: ':SettingsLib')
- compileOnly files(frameworkClassesJar)
-
- implementation 'androidx.core:core-ktx:1.7.0'
- implementation 'androidx.appcompat:appcompat:1.4.1'
- implementation 'androidx.preference:preference-ktx:1.1.1'
- implementation 'com.google.android.material:material:1.5.0'
- implementation 'com.google.code.gson:gson:2.8.6'
- implementation 'com.google.dagger:hilt-android:2.40.5'
- implementation project(path: ':SettingsLibParts')
+ implementation 'androidx.core:core-ktx:1.9.0'
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'androidx.preference:preference-ktx:1.2.0'
+ implementation 'com.google.android.material:material:1.8.0'
+ implementation 'com.google.code.gson:gson:2.10.1'
+ implementation 'com.google.dagger:hilt-android:2.45'
+ implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ kapt 'com.google.dagger:hilt-compiler:2.45'
}
kapt {
correctErrorTypes true
}
-
-allprojects {
- gradle.projectsEvaluated {
- tasks.withType(JavaCompile) {
- options.compilerArgs.add("-Xbootclasspath/p:$frameworkClassesJar")
- }
- }
-}
diff --git a/app/src/main/Android.bp b/app/src/main/Android.bp
index df18d0a9..ee8aa8bc 100644
--- a/app/src/main/Android.bp
+++ b/app/src/main/Android.bp
@@ -24,15 +24,33 @@ android_app {
"com.google.android.material_material",
"kotlin-stdlib",
"kotlinx-coroutines-android",
- "gson-prebuilt-jar",
+ "gson-prebuilt-jar-2.9.1",
"hilt_android",
+ "org.lineageos.platform.internal",
+ "LineagePreferenceLib",
+ "androidx.activity_activity-compose",
+ "androidx.compose.animation_animation-core",
+ "androidx.compose.animation_animation-graphics",
+ "androidx.compose.foundation_foundation",
+ "androidx.compose.material3_material3",
+ "androidx.compose.material3_material3-window-size-class",
+ "androidx.compose.material_material-icons-core",
+ "androidx.compose.material_material-icons-extended",
+ "androidx.compose.runtime_runtime",
+ "androidx.compose.ui_ui",
+ "kotlinx-coroutines-core",
+ "androidx.lifecycle_lifecycle-runtime-compose",
],
kotlincflags: [
- "-Xuse-experimental=kotlin.Experimental",
- "-Xuse-experimental=kotlin.ExperimentalStdlibApi",
+ "-Xjvm-default=all",
+ "-opt-in=kotlin.Experimental",
+ "-opt-in=kotlin.ExperimentalStdlibApi",
+ "-Xopt-in=kotlin.RequiresOptIn",
+ "-P plugin:androidx.compose.compiler.plugins.kotlin:sourceInformation=true",
],
plugins: [
"dagger2-compiler",
+ "androidx.room_room-compiler-plugin",
],
required: [
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4ab8acae..5ad130c6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -26,28 +26,40 @@
-
+
+
+
+
+
+
+
+
+
+ android:theme="@style/GameSpaceTheme"
+ android:enableOnBackInvokedCallback="true">
+ android:exported="true">
+
+
+
+
+
@@ -57,12 +69,22 @@
+
+
+
+
+
+
+ android:permission="android.permission.MANAGE_GAME_MODE">
diff --git a/app/src/main/java/com/crdroid/settings/preferences/CustomSeekBarPreference.java b/app/src/main/java/com/crdroid/settings/preferences/CustomSeekBarPreference.java
new file mode 100644
index 00000000..6b3e78a4
--- /dev/null
+++ b/app/src/main/java/com/crdroid/settings/preferences/CustomSeekBarPreference.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2016-2025 crDroid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.crdroid.settings.preferences;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.res.ResourcesCompat;
+import androidx.core.view.ViewCompat;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import io.chaldeaprjkt.gamespace.R;
+import com.android.settingslib.widget.SliderPreference;
+
+import com.google.android.material.slider.LabelFormatter;
+import com.google.android.material.slider.Slider;
+
+public class CustomSeekBarPreference extends SliderPreference {
+
+ private static final String SETTINGS_NS = "http://schemas.android.com/apk/res/com.android.settings";
+ private static final String ANDROIDNS = "http://schemas.android.com/apk/res/android";
+
+ private boolean mShowSign;
+ @Nullable
+ private String mUnits = "";
+ @Nullable
+ private String mDefaultValueText;
+ private boolean mDefaultValueTextExists;
+ private boolean mDefaultValueExists;
+ private int mDefaultValue;
+
+ private CharSequence mUserSummary;
+
+ private boolean mInUserDrag = false;
+
+ public CustomSeekBarPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ readLegacyAttrs(context, attrs);
+ initDefaults();
+ mUserSummary = super.getSummary();
+ updateSummaryNow();
+ }
+
+ public CustomSeekBarPreference(Context context) {
+ super(context, null);
+ initDefaults();
+ mUserSummary = super.getSummary();
+ updateSummaryNow();
+ }
+
+ private void initDefaults() {
+ setShowSliderValue(true);
+ setHapticFeedbackMode(HAPTIC_FEEDBACK_MODE_ON_TICKS);
+ setLabelFormater(new LabelFormatter() {
+ @Override public String getFormattedValue(float value) {
+ return formatValueForSummary((int) value);
+ }
+ });
+ }
+
+ private void readLegacyAttrs(Context c, AttributeSet attrs) {
+ if (attrs == null) return;
+ final TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.CustomSeekBarPreference);
+ try {
+ mShowSign = a.getBoolean(R.styleable.CustomSeekBarPreference_showSign, false);
+ final String units = a.getString(R.styleable.CustomSeekBarPreference_units);
+ if (units != null) mUnits = units;
+
+ final boolean continuous = a.getBoolean(
+ R.styleable.CustomSeekBarPreference_continuousUpdates, false);
+ setUpdatesContinuously(continuous);
+
+ mDefaultValueText = a.getString(
+ R.styleable.CustomSeekBarPreference_defaultValueText);
+ mDefaultValueTextExists = mDefaultValueText != null && !mDefaultValueText.isEmpty();
+
+ String defaultValue = attrs.getAttributeValue(ANDROIDNS, "defaultValue");
+ if (defaultValue == null) {
+ defaultValue = attrs.getAttributeValue(SETTINGS_NS, "defaultValue");
+ }
+ if (defaultValue != null && !defaultValue.isEmpty()) {
+ try {
+ mDefaultValue = Integer.parseInt(defaultValue);
+ mDefaultValueExists = true;
+ } catch (NumberFormatException ignored) {
+ mDefaultValueExists = false;
+ }
+ }
+
+ int interval = attrs.getAttributeIntValue(SETTINGS_NS, "interval", 0);
+ if (interval == 0) {
+ interval = attrs.getAttributeIntValue(ANDROIDNS, "interval", 0);
+ }
+ if (interval > 0) setSliderIncrement(interval);
+
+ // Guard against improper slider increment
+ int min = getMin();
+ int max = getMax();
+ int span = Math.max(0, max - min);
+
+ int step = getSliderIncrement();
+ if (step <= 0 || span == 0) {
+ setSliderIncrement(1); // Always use discrete steps for CustomSeekBarPreference
+ } else if ((span % step) != 0) {
+ int gcd = gcd(span, step);
+ if (gcd <= 0) gcd = 1;
+ setSliderIncrement(gcd);
+ }
+ } catch (Throwable ignored) {
+ // keep safe defaults
+ } finally {
+ a.recycle();
+ }
+ }
+
+ @Override
+ public void setSummary(CharSequence summary) {
+ mUserSummary = summary;
+ updateSummaryNow();
+ }
+
+ @Override
+ public void setValue(int sliderValue) {
+ super.setValue(sliderValue);
+ if (!mInUserDrag) updateSummaryNow();
+ }
+
+ private void updateSummaryNow() {
+ CharSequence composed = composeSummary(mUserSummary, getValue());
+ super.setSummary(composed);
+ }
+
+ private String formatValueForSummary(int v) {
+ if (mDefaultValueExists && mDefaultValueTextExists && v == mDefaultValue) {
+ return mDefaultValueText;
+ }
+ String s = String.valueOf(v);
+ if (mShowSign && v > 0) s = "+" + s;
+ if (mUnits != null && !mUnits.isEmpty()) s = s + " " + mUnits;
+ return s;
+ }
+
+ private CharSequence composeSummary(CharSequence userSummary, int v) {
+ final String valueText = formatValueForSummary(v);
+ if (userSummary == null || userSummary.length() == 0) return valueText;
+ return valueText + " \u2022 " + userSummary;
+ }
+
+ @Override
+ public void setDefaultValue(Object defaultValue) {
+ if (defaultValue instanceof Integer) {
+ mDefaultValueExists = true;
+ mDefaultValue = (Integer) defaultValue;
+ }
+ super.setDefaultValue(defaultValue);
+ updateSummaryNow();
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+ if (summaryView != null) {
+ summaryView.setText(composeSummary(mUserSummary, getValue()));
+ }
+
+ final View labelFrame = holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.label_frame);
+ final TextView startText = (TextView) holder.findViewById(android.R.id.text1);
+ final TextView endText = (TextView) holder.findViewById(android.R.id.text2);
+
+ if (labelFrame != null) {
+ boolean hasStart = startText != null && startText.getText() != null
+ && startText.getText().length() > 0;
+ boolean hasEnd = endText != null && endText.getText() != null
+ && endText.getText().length() > 0;
+ boolean parentWantsLabels = hasStart || hasEnd;
+
+ labelFrame.setVisibility((parentWantsLabels || mDefaultValueExists) ? View.VISIBLE : View.GONE);
+ }
+
+ if (endText != null) {
+ attachResetIcon(endText);
+ }
+
+ ViewGroup minusFrame = (ViewGroup) holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.icon_start_frame);
+ ImageView minusIcon = (ImageView) holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.icon_start);
+
+ ViewGroup plusFrame = (ViewGroup) holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.icon_end_frame);
+ ImageView plusIcon = (ImageView) holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.icon_end);
+
+ final Slider slider = (Slider) holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.slider);
+
+ int stepForClicks = Math.max(1, getSliderIncrement());
+
+ if (minusFrame != null && minusIcon != null) {
+ minusFrame.setVisibility(View.VISIBLE);
+ minusIcon.setImageResource(R.drawable.ic_custom_seekbar_minus);
+ minusFrame.setOnClickListener(v -> {
+ if (!isEnabled()) return;
+ int base = slider != null ? Math.round(slider.getValue()) : getValue();
+ int newVal = Math.max(getMin(), base - stepForClicks);
+ applyUserValue(newVal, slider);
+ updatePlusMinusEnabledStates(holder);
+ });
+ }
+
+ if (plusFrame != null && plusIcon != null) {
+ plusFrame.setVisibility(View.VISIBLE);
+ plusIcon.setImageResource(R.drawable.ic_custom_seekbar_plus);
+ plusFrame.setOnClickListener(v -> {
+ if (!isEnabled()) return;
+ int base = slider != null ? Math.round(slider.getValue()) : getValue();
+ int newVal = Math.min(getMax(), base + stepForClicks);
+ applyUserValue(newVal, slider);
+ updatePlusMinusEnabledStates(holder);
+ });
+ }
+
+ updatePlusMinusEnabledStates(holder);
+
+ if (slider != null && summaryView != null) {
+ slider.addOnChangeListener((s, value, fromUser) -> {
+ if (fromUser) {
+ summaryView.setText(composeSummary(mUserSummary, (int) value));
+ updatePlusMinusEnabledStates(holder);
+ }
+ });
+ slider.addOnSliderTouchListener(new Slider.OnSliderTouchListener() {
+ @Override
+ public void onStartTrackingTouch(@NonNull Slider s) {
+ mInUserDrag = true;
+ }
+
+ @Override
+ public void onStopTrackingTouch(@NonNull Slider s) {
+ mInUserDrag = false;
+ applyUserValue(Math.round(s.getValue()), s);
+ updatePlusMinusEnabledStates(holder);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onDependencyChanged(@NonNull Preference dependency, boolean disableDependent) {
+ super.onDependencyChanged(dependency, disableDependent);
+ notifyChanged();
+ }
+
+ private void applyUserValue(int newVal, @Nullable Slider slider) {
+ if (newVal == getValue()) return;
+ if (!callChangeListener(newVal)) {
+ if (slider != null) slider.setValue(getValue());
+ return;
+ }
+ setValue(newVal);
+ updateSummaryNow();
+ notifyChanged();
+ }
+
+ private static int gcd(int a, int b) {
+ a = Math.abs(a); b = Math.abs(b);
+ if (a == 0) return b;
+ if (b == 0) return a;
+ while (b != 0) {
+ int t = b; b = a % b; a = t;
+ }
+ return a;
+ }
+
+ private void updatePlusMinusEnabledStates(PreferenceViewHolder holder) {
+ View minusFrame = holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.icon_start_frame);
+ ImageView minusIcon = (ImageView) holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.icon_start);
+ View plusFrame = holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.icon_end_frame);
+ ImageView plusIcon = (ImageView) holder.findViewById(
+ com.android.settingslib.widget.preference.slider.R.id.icon_end);
+ boolean enabled = isEnabled();
+ int value = getValue();
+
+ if (minusFrame != null && minusIcon != null) {
+ int min = getMin();
+ minusFrame.setEnabled(enabled && (value > min));
+ minusIcon.setEnabled(enabled && (value > min));
+ }
+ if (plusFrame != null && plusIcon != null) {
+ int max = getMax();
+ plusFrame.setEnabled(enabled && (value < max));
+ plusIcon.setEnabled(enabled && (value < max));
+ }
+ }
+
+ private void attachResetIcon(TextView tv) {
+ if (!mDefaultValueExists) {
+ tv.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, null, null);
+ tv.setOnTouchListener(null);
+ tv.setClickable(false);
+ return;
+ }
+
+ final Drawable icon = ResourcesCompat.getDrawable(
+ tv.getResources(), R.drawable.ic_custom_seekbar_reset, tv.getContext().getTheme());
+ if (icon == null) return;
+
+ tv.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, icon, null);
+ tv.setCompoundDrawablePadding(dp(tv, 6));
+ tv.setClickable(isEnabled());
+ tv.setFocusable(isEnabled());
+
+ final int tapSlop = dp(tv, 8);
+
+ tv.setOnTouchListener((v, ev) -> {
+ if (!isEnabled() || ev.getAction() != MotionEvent.ACTION_UP) return false;
+
+ final boolean isRtl = ViewCompat.getLayoutDirection(tv) == ViewCompat.LAYOUT_DIRECTION_RTL;
+ final Drawable[] drs = tv.getCompoundDrawablesRelative();
+ final Drawable end = drs[2];
+ if (end == null) return false;
+
+ final int iconW = end.getIntrinsicWidth();
+ final int x = (int) ev.getX();
+
+ if (!isRtl) {
+ final int left = tv.getWidth() - ViewCompat.getPaddingEnd(tv) - iconW - tapSlop;
+ if (x >= left) { performReset(); return true; }
+ } else {
+ final int right = ViewCompat.getPaddingStart(tv) + iconW + tapSlop;
+ if (x <= right) { performReset(); return true; }
+ }
+ return false;
+ });
+ }
+
+ private void performReset() {
+ if (mDefaultValueExists) {
+ applyUserValue(mDefaultValue, null);
+ }
+ }
+
+ private static int dp(TextView v, int dp) {
+ return Math.round(dp * v.getResources().getDisplayMetrics().density);
+ }
+}
diff --git a/app/src/main/java/com/crdroid/settings/preferences/SystemSettingListPreference.java b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingListPreference.java
new file mode 100644
index 00000000..99679d23
--- /dev/null
+++ b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingListPreference.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016-2018 crDroid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.crdroid.settings.preferences;
+
+import android.content.Context;
+import androidx.preference.ListPreference;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.provider.Settings;
+
+public class SystemSettingListPreference extends ListPreference {
+
+ private boolean mAutoSummary = false;
+
+ public SystemSettingListPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+ }
+
+ public SystemSettingListPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+ }
+
+ public SystemSettingListPreference(Context context) {
+ super(context);
+ setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+ }
+
+ @Override
+ public void setValue(String value) {
+ super.setValue(value);
+ if (mAutoSummary || TextUtils.isEmpty(getSummary())) {
+ setSummary(getEntry(), true);
+ }
+ }
+
+ @Override
+ public void setSummary(CharSequence summary) {
+ setSummary(summary, false);
+ }
+
+ private void setSummary(CharSequence summary, boolean autoSummary) {
+ mAutoSummary = autoSummary;
+ super.setSummary(summary);
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ // This is what default ListPreference implementation is doing without respecting
+ // real default value:
+ //setValue(restoreValue ? getPersistedString(mValue) : (String) defaultValue);
+ // Instead, we better do
+ setValue(restoreValue ? getPersistedString((String) defaultValue) : (String) defaultValue);
+ }
+
+ public int getIntValue(int defValue) {
+ return getValue() == null ? defValue : Integer.valueOf(getValue());
+ }
+}
diff --git a/app/src/main/java/com/crdroid/settings/preferences/SystemSettingMainSwitchPreference.java b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingMainSwitchPreference.java
new file mode 100644
index 00000000..e12878c6
--- /dev/null
+++ b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingMainSwitchPreference.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016-2022 crDroid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.crdroid.settings.preferences;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.os.UserHandle;
+import android.util.AttributeSet;
+
+import com.android.settingslib.widget.MainSwitchPreference;
+
+import com.crdroid.settings.preferences.SystemSettingsStore;
+
+public class SystemSettingMainSwitchPreference extends MainSwitchPreference {
+
+ public SystemSettingMainSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+ }
+
+ public SystemSettingMainSwitchPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+ }
+
+ public SystemSettingMainSwitchPreference(Context context) {
+ super(context);
+ setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+ }
+}
diff --git a/app/src/main/java/com/crdroid/settings/preferences/SystemSettingSeekBarPreference.java b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingSeekBarPreference.java
new file mode 100644
index 00000000..520c65d8
--- /dev/null
+++ b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingSeekBarPreference.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016-2025 crDroid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.crdroid.settings.preferences;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+public class SystemSettingSeekBarPreference extends CustomSeekBarPreference {
+
+ public SystemSettingSeekBarPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+ }
+
+ public SystemSettingSeekBarPreference(Context context) {
+ super(context, null);
+ setPreferenceDataStore(new SystemSettingsStore(context.getContentResolver()));
+ }
+}
diff --git a/app/src/main/java/com/crdroid/settings/preferences/SystemSettingSwitchPreference.java b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingSwitchPreference.java
new file mode 100644
index 00000000..98526e47
--- /dev/null
+++ b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingSwitchPreference.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2016-2018 crDroid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.crdroid.settings.preferences;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.os.UserHandle;
+import android.util.AttributeSet;
+
+import lineageos.preference.SelfRemovingSwitchPreference;
+
+public class SystemSettingSwitchPreference extends SelfRemovingSwitchPreference {
+
+ public SystemSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public SystemSettingSwitchPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SystemSettingSwitchPreference(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected boolean isPersisted() {
+ return Settings.System.getString(getContext().getContentResolver(), getKey()) != null;
+ }
+
+ @Override
+ protected void putBoolean(String key, boolean value) {
+ Settings.System.putIntForUser(getContext().getContentResolver(), key, value ? 1 : 0, UserHandle.USER_CURRENT);
+ }
+
+ @Override
+ protected boolean getBoolean(String key, boolean defaultValue) {
+ return Settings.System.getIntForUser(getContext().getContentResolver(),
+ key, defaultValue ? 1 : 0, UserHandle.USER_CURRENT) != 0;
+ }
+}
diff --git a/app/src/main/java/com/crdroid/settings/preferences/SystemSettingsStore.java b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingsStore.java
new file mode 100644
index 00000000..e7bb41b8
--- /dev/null
+++ b/app/src/main/java/com/crdroid/settings/preferences/SystemSettingsStore.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016-2018 crDroid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.crdroid.settings.preferences;
+
+import android.content.ContentResolver;
+import android.preference.PreferenceDataStore;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+public class SystemSettingsStore extends androidx.preference.PreferenceDataStore
+ implements PreferenceDataStore {
+
+ private ContentResolver mContentResolver;
+
+ public SystemSettingsStore(ContentResolver contentResolver) {
+ mContentResolver = contentResolver;
+ }
+
+ public boolean getBoolean(String key, boolean defValue) {
+ return Settings.System.getIntForUser(mContentResolver, key, defValue ? 1 : 0, UserHandle.USER_CURRENT) != 0;
+ }
+
+ public float getFloat(String key, float defValue) {
+ return Settings.System.getFloatForUser(mContentResolver, key, defValue, UserHandle.USER_CURRENT);
+ }
+
+ public int getInt(String key, int defValue) {
+ return Settings.System.getIntForUser(mContentResolver, key, defValue, UserHandle.USER_CURRENT);
+ }
+
+ public long getLong(String key, long defValue) {
+ return Settings.System.getLongForUser(mContentResolver, key, defValue, UserHandle.USER_CURRENT);
+ }
+
+ public String getString(String key, String defValue) {
+ String result = Settings.System.getString(mContentResolver, key);
+ return result == null ? defValue : result;
+ }
+
+ public void putBoolean(String key, boolean value) {
+ putInt(key, value ? 1 : 0);
+ }
+
+ public void putFloat(String key, float value) {
+ Settings.System.putFloatForUser(mContentResolver, key, value, UserHandle.USER_CURRENT);
+ }
+
+ public void putInt(String key, int value) {
+ Settings.System.putIntForUser(mContentResolver, key, value, UserHandle.USER_CURRENT);
+ }
+
+ public void putLong(String key, long value) {
+ Settings.System.putLongForUser(mContentResolver, key, value, UserHandle.USER_CURRENT);
+ }
+
+ public void putString(String key, String value) {
+ Settings.System.putString(mContentResolver, key, value);
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/data/AppSettings.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/data/AppSettings.kt
index 98ac3840..f1baf0e6 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/data/AppSettings.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/data/AppSettings.kt
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022-2024 crDroid Android Project
+ * 2023 risingOS Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,11 +42,6 @@ class AppSettings @Inject constructor(private val context: Context) {
get() = db.getBoolean("show_fps", false)
set(point) = db.edit().putBoolean("show_fps", point).apply()
- var noHeadsUp
- get() = db.getBoolean(KEY_HEADS_UP_DISABLE, true)
- set(it) = db.edit().putBoolean(KEY_HEADS_UP_DISABLE, it).apply()
-
-
var noAutoBrightness
get() = db.getBoolean(KEY_AUTO_BRIGHTNESS_DISABLE, true)
set(it) = db.edit().putBoolean(KEY_AUTO_BRIGHTNESS_DISABLE, it).apply()
@@ -57,15 +54,44 @@ class AppSettings @Inject constructor(private val context: Context) {
get() = db.getBoolean(KEY_STAY_AWAKE, false)
set(value) = db.edit().putBoolean(KEY_STAY_AWAKE, value).apply()
+ var danmakuNotification
+ get() = db.getBoolean(KEY_DANMAKU_NOTIFICATION_MODE, true)
+ set(value) = db.edit().putBoolean(KEY_DANMAKU_NOTIFICATION_MODE, value).apply()
+
+ var callsMode: Int
+ get() = db.getString(KEY_CALLS_MODE, "0")?.toIntOrNull() ?: 0
+ set(value) = db.edit().putString(KEY_CALLS_MODE, value.toString()).apply()
+
var ringerMode: Int
- get() = db.getString(KEY_RINGER_MODE, "0").toInt()
+ get() = db.getString(KEY_RINGER_MODE, "3")?.toIntOrNull() ?: 3
set(value) = db.edit().putString(KEY_RINGER_MODE, value.toString()).apply()
+ var menuOpacity: Int
+ get() = db.getInt(KEY_MENU_OPACITY, 100)
+ set(value) = db.edit().putInt(KEY_MENU_OPACITY, value).apply()
+
+ var noAdbEnabled
+ get() = db.getBoolean(KEY_ADB_DISABLE, false)
+ set(it) = db.edit().putBoolean(KEY_ADB_DISABLE, it).apply()
+
+ var lockGesture
+ get() = db.getBoolean(KEY_LOCK_GESTURE, false)
+ set(value) = db.edit().putBoolean(KEY_LOCK_GESTURE, value).apply()
+
+ var callOverlayEnabled
+ get() = db.getBoolean(KEY_CALL_OVERLAY_ENABLED, true)
+ set(point) = db.edit().putBoolean(KEY_CALL_OVERLAY_ENABLED, point).apply()
+
companion object {
- const val KEY_HEADS_UP_DISABLE = "gamespace_heads_up_disabled"
const val KEY_AUTO_BRIGHTNESS_DISABLE = "gamespace_auto_brightness_disabled"
const val KEY_3SCREENSHOT_DISABLE = "gamespace_tfgesture_disabled"
const val KEY_STAY_AWAKE = "gamespace_stay_awake"
+ const val KEY_DANMAKU_NOTIFICATION_MODE = "gamespace_danmaku_notification_mode"
+ const val KEY_CALLS_MODE = "gamespace_calls_mode"
const val KEY_RINGER_MODE = "gamespace_ringer_mode"
+ const val KEY_MENU_OPACITY = "gamespace_menu_opacity"
+ const val KEY_ADB_DISABLE = "gamespace_adb_disabled"
+ const val KEY_LOCK_GESTURE = "gamespace_lock_gesture"
+ const val KEY_CALL_OVERLAY_ENABLED = "call_overlay_enabled"
}
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/data/GameOptimizationManager.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/data/GameOptimizationManager.kt
new file mode 100644
index 00000000..e7820c17
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/data/GameOptimizationManager.kt
@@ -0,0 +1,121 @@
+/*
+ * SPDX-FileCopyrightText: 2025 DerpFest AOSP
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package io.chaldeaprjkt.gamespace.data
+
+import android.app.ActivityManager
+import android.content.Context
+import android.content.ComponentCallbacks2
+import android.content.SharedPreferences
+import android.os.Process
+import dagger.hilt.android.qualifiers.ApplicationContext
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class GameOptimizationManager @Inject constructor(
+ @ApplicationContext private val context: Context
+) {
+ private val prefs: SharedPreferences = context.getSharedPreferences(
+ "game_optimization_settings",
+ Context.MODE_PRIVATE
+ )
+
+ private val activityManager: ActivityManager = context.getSystemService(ActivityManager::class.java)
+
+ var isLaunchBoostEnabled: Boolean
+ get() = prefs.getBoolean(KEY_LAUNCH_BOOST, true)
+ set(value) = prefs.edit().putBoolean(KEY_LAUNCH_BOOST, value).apply()
+
+ var isMemoryManagementEnabled: Boolean
+ get() = prefs.getBoolean(KEY_MEMORY_MANAGEMENT, false)
+ set(value) = prefs.edit().putBoolean(KEY_MEMORY_MANAGEMENT, value).apply()
+
+ var loadPriority: String
+ get() = prefs.getString(KEY_LOAD_PRIORITY, "balanced") ?: "balanced"
+ set(value) = prefs.edit().putString(KEY_LOAD_PRIORITY, value).apply()
+
+ var isCacheManagementEnabled: Boolean
+ get() = prefs.getBoolean(KEY_CACHE_MANAGEMENT, true)
+ set(value) = prefs.edit().putBoolean(KEY_CACHE_MANAGEMENT, value).apply()
+
+ fun optimizeGameLaunch(packageName: String) {
+ if (isLaunchBoostEnabled) {
+ // Set process priority to foreground
+ Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND)
+ }
+
+ if (isMemoryManagementEnabled) {
+ clearBackgroundProcesses()
+ }
+
+ when (loadPriority) {
+ "performance" -> {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY)
+ trimMemory(ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW)
+ }
+ "powersave" -> {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND)
+ trimMemory(ComponentCallbacks2.TRIM_MEMORY_COMPLETE)
+ }
+ else -> {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT)
+ trimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE)
+ }
+ }
+
+ if (isCacheManagementEnabled) {
+ optimizeGameCache(packageName)
+ }
+ }
+
+ private fun trimMemory(level: Int) {
+ try {
+ val runtimeTrimMemory = ActivityManager::class.java.getMethod("trimMemory", Int::class.java)
+ runtimeTrimMemory.invoke(activityManager, level)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+ private fun clearBackgroundProcesses() {
+ val runningApps = activityManager.runningAppProcesses ?: return
+ runningApps.forEach { processInfo ->
+ if (processInfo.importance > ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ activityManager.killBackgroundProcesses(processInfo.processName)
+ }
+ }
+ }
+
+ private fun optimizeGameCache(packageName: String) {
+ try {
+ // Clear package cache if it's too large
+ val packageInfo = context.packageManager.getPackageInfo(packageName, 0)
+ packageInfo.applicationInfo?.dataDir?.let { dataDir ->
+ val dir = java.io.File(dataDir)
+ if (dir.exists()) {
+ val cacheSize = dir.walkTopDown()
+ .filter { it.isFile }
+ .map { it.length() }
+ .sum()
+
+ if (cacheSize > CACHE_THRESHOLD) {
+ context.packageManager.clearPackagePreferredActivities(packageName)
+ }
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+ companion object {
+ private const val KEY_LAUNCH_BOOST = "launch_boost"
+ private const val KEY_MEMORY_MANAGEMENT = "memory_management"
+ private const val KEY_LOAD_PRIORITY = "load_priority"
+ private const val KEY_CACHE_MANAGEMENT = "cache_management"
+ private const val CACHE_THRESHOLD = 100 * 1024 * 1024L // 100MB
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/data/GameSession.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/data/GameSession.kt
index aad6c6b3..5f26c6c9 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/data/GameSession.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/data/GameSession.kt
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * 2022 crDroid Android Project
+ * Copyright (C) 2023 risingOS Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,34 +58,45 @@ class GameSession @Inject constructor(
state = SessionState(
packageName = sessionName,
autoBrightness = systemSettings.autoBrightness,
- headsUp = systemSettings.headsUp,
+ headsup = systemSettings.headsup,
threeScreenshot = systemSettings.threeScreenshot,
ringerMode = audioManager.ringerModeInternal,
+ adbEnabled = systemSettings.adbEnabled,
)
- if (appSettings.noHeadsUp) {
- systemSettings.headsUp = false
- }
if (appSettings.noAutoBrightness) {
systemSettings.autoBrightness = false
}
+ if (appSettings.danmakuNotification) {
+ systemSettings.headsup = false
+ }
if (appSettings.noThreeScreenshot) {
- systemSettings.threeScreenshot = false
+ systemSettings.threeScreenshot = 0
+ }
+ if (appSettings.noAdbEnabled) {
+ systemSettings.adbEnabled = false
+ }
+ if (appSettings.ringerMode != 3) {
+ audioManager.ringerModeInternal = appSettings.ringerMode
}
- audioManager.ringerModeInternal = appSettings.ringerMode
}
fun unregister() {
val orig = state?.copy() ?: return
- if (appSettings.noHeadsUp) {
- orig.headsUp?.let { systemSettings.headsUp = it }
- }
if (appSettings.noAutoBrightness) {
orig.autoBrightness?.let { systemSettings.autoBrightness = it }
}
+ if (appSettings.danmakuNotification) {
+ orig.headsup?.let { systemSettings.headsup = it }
+ }
if (appSettings.noThreeScreenshot) {
- orig.threeScreenshot?.let { systemSettings.threeScreenshot = it }
+ systemSettings.threeScreenshot = orig.threeScreenshot
+ }
+ if (appSettings.noAdbEnabled) {
+ orig.adbEnabled?.let { systemSettings.adbEnabled = it }
+ }
+ if (appSettings.ringerMode != 3) {
+ audioManager.ringerModeInternal = orig.ringerMode
}
- audioManager.ringerModeInternal = orig.ringerMode
state = null
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/data/SessionState.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/data/SessionState.kt
index 5cbe3e6f..6ea42078 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/data/SessionState.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/data/SessionState.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * 2022-2024 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +23,8 @@ import androidx.annotation.Keep
data class SessionState(
var packageName: String,
var autoBrightness: Boolean? = null,
- var headsUp: Boolean? = null,
- var threeScreenshot: Boolean? = null,
+ var headsup: Boolean? = null,
+ var threeScreenshot: Int = 0,
var ringerMode: Int = AudioManager.RINGER_MODE_NORMAL,
+ var adbEnabled: Boolean? = null,
)
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/data/SystemSettings.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/data/SystemSettings.kt
index 5e88dca8..9e245f11 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/data/SystemSettings.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/data/SystemSettings.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * 2022 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +22,8 @@ import android.provider.Settings
import io.chaldeaprjkt.gamespace.utils.GameModeUtils
import javax.inject.Inject
+import lineageos.providers.LineageSettings
+
class SystemSettings @Inject constructor(
context: Context,
private val gameModeUtils: GameModeUtils
@@ -28,13 +31,12 @@ class SystemSettings @Inject constructor(
private val resolver = context.contentResolver
- var headsUp
- get() =
- Settings.Global.getInt(resolver, Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1) == 1
+ var headsup
+ get() = Settings.Global.getInt(
+ resolver, Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, 1) == 1
set(it) {
Settings.Global.putInt(
- resolver,
- Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+ resolver, Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
it.toInt()
)
}
@@ -59,30 +61,14 @@ class SystemSettings @Inject constructor(
}
var threeScreenshot
- get() = Settings.System.getIntForUser(
- resolver, Settings.System.THREE_FINGER_GESTURE, 0,
+ get() = LineageSettings.System.getIntForUser(
+ resolver, LineageSettings.System.KEY_THREE_FINGERS_SWIPE_ACTION, 0,
UserHandle.USER_CURRENT
- ) == 1
- set(it) {
- Settings.System.putIntForUser(
- resolver, Settings.System.THREE_FINGER_GESTURE,
- it.toInt(), UserHandle.USER_CURRENT
- )
- }
-
- var suppressFullscreenIntent
- get() = Settings.System.getIntForUser(
- resolver,
- Settings.System.GAMESPACE_SUPPRESS_FULLSCREEN_INTENT,
- 0,
- UserHandle.USER_CURRENT
- ) == 1
- set(it) {
- Settings.System.putIntForUser(
- resolver,
- Settings.System.GAMESPACE_SUPPRESS_FULLSCREEN_INTENT,
- it.toInt(),
- UserHandle.USER_CURRENT
+ )
+ set(value) {
+ LineageSettings.System.putIntForUser(
+ resolver, LineageSettings.System.KEY_THREE_FINGERS_SWIPE_ACTION,
+ value, UserHandle.USER_CURRENT
)
}
@@ -106,5 +92,16 @@ class SystemSettings @Inject constructor(
gameModeUtils.setupBatteryMode(games.isNotEmpty())
}
+ var adbEnabled
+ get() = Settings.Global.getInt(
+ resolver, Settings.Global.ADB_ENABLED, 0
+ ) == 1
+ set(it) {
+ Settings.Global.putInt(
+ resolver, Settings.Global.ADB_ENABLED,
+ it.toInt()
+ )
+ }
+
private fun Boolean.toInt() = if (this) 1 else 0
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/CallListener.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/CallListener.kt
new file mode 100644
index 00000000..aa2e7de9
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/CallListener.kt
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2020 The exTHmUI Open Source Project
+ * Copyright (C) 2021 AOSP-Krypton Project
+ * Copyright (C) 2022 Nameless-AOSP Project
+ * Copyright (C) 2022-2024 crDroid Android Project
+ * Copyright (C) 2023 the risingOS Android Project
+ * Copyright (C) 2025 AxionOS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.chaldeaprjkt.gamespace.gamebar
+
+import android.content.Context
+import android.graphics.BitmapFactory
+import android.graphics.PixelFormat
+import android.media.AudioDeviceInfo
+import android.media.AudioManager
+import android.media.AudioSystem
+import android.net.Uri
+import android.provider.ContactsContract
+import android.telecom.TelecomManager
+import android.telephony.PhoneStateListener
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyManager
+import android.util.TypedValue
+import android.view.Gravity
+import android.view.View
+import android.view.WindowManager
+import android.widget.Toast
+import androidx.compose.animation.*
+import androidx.compose.animation.core.*
+import androidx.compose.foundation.*
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Call
+import androidx.compose.material.icons.filled.Close
+import androidx.compose.material.icons.filled.KeyboardArrowDown
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.*
+import androidx.compose.ui.graphics.*
+import androidx.compose.ui.layout.*
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.ViewCompositionStrategy
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.android.scopes.ServiceScoped
+import io.chaldeaprjkt.gamespace.R
+import io.chaldeaprjkt.gamespace.data.AppSettings
+import io.chaldeaprjkt.gamespace.gamebar.lifecycle.repeatWhenAttached
+import io.chaldeaprjkt.gamespace.utils.dp as extDp
+import javax.inject.Inject
+import kotlinx.coroutines.*
+
+@ServiceScoped
+class CallListener @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val appSettings: AppSettings
+) {
+ private val audioManager = context.getSystemService(AudioManager::class.java)!!
+ private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
+ private val telecomManager = context.getSystemService(TelecomManager::class.java)!!
+ private val windowManager = context.getSystemService(WindowManager::class.java)!!
+
+ private val callsMode = appSettings.callsMode
+ private val callOverlayEnabled = appSettings.callOverlayEnabled
+ private var previousAudioMode = audioManager.mode
+
+ private var ringerOverlay: ComposeView? = null
+ private var isOverlayShowing = false
+
+ private val phoneStateListener = object: PhoneStateListener() {
+ override fun onCallStateChanged(state: Int, incomingNumber: String?) {
+ if (state == TelephonyManager.CALL_STATE_RINGING && callOverlayEnabled) {
+ showRingerOverlay(incomingNumber)
+ }
+ }
+ }
+
+ private val telephonyCallback = object : TelephonyCallback(), TelephonyCallback.CallStateListener {
+ override fun onCallStateChanged(state: Int) {
+ when (state) {
+ TelephonyManager.CALL_STATE_RINGING -> {
+ handleIncomingCall()
+ }
+ TelephonyManager.CALL_STATE_OFFHOOK -> handleOffhookState()
+ TelephonyManager.CALL_STATE_IDLE -> handleIdleState()
+ }
+ }
+ }
+
+ fun init() {
+ telephonyManager.registerTelephonyCallback(context.mainExecutor, telephonyCallback)
+ telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
+ }
+
+ fun destroy() {
+ telephonyManager.unregisterTelephonyCallback(telephonyCallback)
+ dismissRingerOverlay(immediate = true)
+ telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE)
+ }
+
+ private fun handleIncomingCall() {
+ if (callsMode == 0) return
+
+ when (callsMode) {
+ 1 -> {
+ telecomManager.acceptRingingCall()
+ Toast.makeText(
+ context,
+ context.getString(R.string.in_game_calls_received_number, ""),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ 2 -> {
+ telecomManager.endCall()
+ Toast.makeText(
+ context,
+ context.getString(R.string.in_game_calls_rejected_number, ""),
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+
+ private fun handleOffhookState() {
+ dismissRingerOverlay()
+
+ if (callsMode == 0 || callsMode == 2) return
+
+ if (isHeadsetPluggedIn()) {
+ audioManager.isSpeakerphoneOn = false
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE)
+ } else {
+ audioManager.isSpeakerphoneOn = true
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER)
+ }
+ audioManager.mode = AudioManager.MODE_IN_COMMUNICATION
+ }
+
+ private fun handleIdleState() {
+ dismissRingerOverlay()
+
+ if (callsMode == 0 || callsMode == 2) return
+
+ audioManager.mode = previousAudioMode
+ AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE)
+ }
+
+ private fun isHeadsetPluggedIn(): Boolean {
+ val devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)!!
+ return devices.any {
+ it.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES ||
+ it.type == AudioDeviceInfo.TYPE_WIRED_HEADSET ||
+ it.type == AudioDeviceInfo.TYPE_USB_HEADSET
+ }
+ }
+
+ private fun showRingerOverlay(incomingNumber: String?) {
+ if (isOverlayShowing) return
+
+ val sidebarX = appSettings.x
+
+ val layoutParams = WindowManager.LayoutParams(
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.WRAP_CONTENT,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ PixelFormat.TRANSLUCENT
+ ).apply {
+ gravity = if (sidebarX < 0)
+ Gravity.TOP or Gravity.END
+ else
+ Gravity.TOP or Gravity.START
+
+ x = 1
+ y = appSettings.y - 71.extDp
+ }
+
+ val callerPhoto = if (incomingNumber.isNullOrEmpty()) null else loadContactPhoto(context, incomingNumber)
+
+ ringerOverlay = ComposeView(context).apply {
+ repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ setViewCompositionStrategy(
+ ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
+ )
+ setContent {
+ val isDark = isSystemInDarkTheme()
+ val scheme = if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
+ MaterialTheme(colorScheme = scheme) {
+ CallOverlay(
+ onAccept = {
+ telecomManager.acceptRingingCall()
+ handleOffhookState()
+ dismissRingerOverlay()
+ },
+ onReject = {
+ telecomManager.endCall()
+ dismissRingerOverlay()
+ },
+ onDismiss = { dismissRingerOverlay() },
+ alignRight = sidebarX < 0,
+ onDismissAnimation = { dismissRingerOverlay() },
+ callerPhoto = callerPhoto
+ )
+ }
+ }
+ }
+ }
+ }
+
+ try {
+ windowManager.addView(ringerOverlay, layoutParams)
+ isOverlayShowing = true
+ } catch (e: Exception) {
+ e.printStackTrace()
+ isOverlayShowing = false
+ }
+ }
+
+ private fun dismissRingerOverlay(immediate: Boolean = false) {
+ ringerOverlay?.let { overlay ->
+ try {
+ if (overlay.isAttachedToWindow) {
+ if (immediate) {
+ windowManager.removeViewImmediate(overlay)
+ } else {
+ overlay.postDelayed({
+ try {
+ windowManager.removeViewImmediate(overlay)
+ } catch (_: Exception) { }
+ }, 300)
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ } finally {
+ ringerOverlay = null
+ isOverlayShowing = false
+ }
+ }
+ }
+
+ fun loadContactPhoto(context: Context, phoneNumber: String): ImageBitmap? {
+ val resolver = context.contentResolver
+ val uri = Uri.withAppendedPath(
+ ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(phoneNumber)
+ )
+
+ resolver.query(uri, arrayOf(ContactsContract.PhoneLookup.PHOTO_URI), null, null, null)?.use { cursor ->
+ if (cursor.moveToFirst()) {
+ val photoUri = cursor.getString(0) ?: return null
+ resolver.openInputStream(Uri.parse(photoUri))?.use { stream ->
+ return BitmapFactory.decodeStream(stream)?.asImageBitmap()
+ }
+ }
+ }
+ return null
+ }
+}
+
+@Composable
+fun CallOverlay(
+ onAccept: () -> Unit,
+ onReject: () -> Unit,
+ onDismiss: () -> Unit,
+ alignRight: Boolean,
+ onDismissAnimation: suspend () -> Unit,
+ callerPhoto: ImageBitmap? = null
+) {
+ var isVisible by remember { mutableStateOf(false) }
+ var isDismissing by remember { mutableStateOf(false) }
+ var btnPressed by remember { mutableStateOf(false) }
+
+ val scale by animateFloatAsState(
+ targetValue = when {
+ isDismissing -> 0f
+ isVisible -> 1f
+ else -> 0f
+ },
+ animationSpec = tween(250, easing = FastOutSlowInEasing),
+ label = "shrink_scale"
+ )
+
+ val fadeAlpha by animateFloatAsState(
+ targetValue = if (isDismissing) 0f else 1f,
+ animationSpec = tween(250),
+ label = "fade"
+ )
+
+ val infiniteTransition = rememberInfiniteTransition(label = "pulse")
+ val pulseAlpha by infiniteTransition.animateFloat(
+ initialValue = 0.6f,
+ targetValue = 1f,
+ animationSpec = infiniteRepeatable(
+ animation = tween(1000, easing = FastOutSlowInEasing),
+ repeatMode = RepeatMode.Reverse
+ ),
+ label = "pulse_alpha"
+ )
+
+ val buttonScale by animateFloatAsState(
+ targetValue = if (btnPressed) 0.85f else 1f,
+ animationSpec = tween(100, easing = LinearOutSlowInEasing),
+ label = "button_press"
+ )
+
+ var showPhoto by remember { mutableStateOf(false) }
+ var acceptAlpha by remember { mutableStateOf(1f) }
+ var photoAlpha by remember { mutableStateOf(0f) }
+
+ LaunchedEffect(Unit) {
+ isVisible = true
+ while (isVisible) {
+ showPhoto = false
+ acceptAlpha = 1f
+ photoAlpha = 0f
+ delay(1500)
+
+ animate(
+ initialValue = 1f,
+ targetValue = 0f,
+ animationSpec = tween(500)
+ ) { value, _ -> acceptAlpha = value }
+ showPhoto = true
+
+ animate(
+ initialValue = 0f,
+ targetValue = 1f,
+ animationSpec = tween(500)
+ ) { value, _ -> photoAlpha = value }
+
+ delay(1500)
+
+ animate(
+ initialValue = 1f,
+ targetValue = 0f,
+ animationSpec = tween(500)
+ ) { value, _ -> photoAlpha = value }
+ }
+ }
+
+ LaunchedEffect(isDismissing) {
+ if (isDismissing) {
+ isVisible = false
+ delay(250)
+ onDismissAnimation()
+ }
+ }
+
+ Box(
+ modifier = Modifier
+ .padding(horizontal = 12.dp, vertical = 8.dp)
+ .graphicsLayer(
+ scaleX = scale,
+ scaleY = scale,
+ alpha = fadeAlpha
+ ),
+ contentAlignment = if (alignRight) Alignment.TopEnd else Alignment.TopStart
+ ) {
+ Column(
+ verticalArrangement = Arrangement.spacedBy(12.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.surfaceContainerHighest)
+ .padding(12.dp)
+ .shadow(8.dp, CircleShape)
+ ) {
+ IconButton(
+ onClick = {
+ btnPressed = true
+ onReject()
+ isDismissing = true
+ },
+ modifier = Modifier
+ .size(56.dp)
+ .scale(buttonScale)
+ .clip(CircleShape)
+ .background(Color(0xFFEF5350))
+ ) {
+ Icon(
+ imageVector = Icons.Filled.Close,
+ contentDescription = "Reject",
+ tint = Color.White.copy(alpha = pulseAlpha),
+ modifier = Modifier.size(28.dp)
+ )
+ }
+
+ Box(
+ modifier = Modifier.size(56.dp),
+ contentAlignment = Alignment.Center
+ ) {
+ IconButton(
+ onClick = {
+ btnPressed = true
+ onAccept()
+ isDismissing = true
+ },
+ modifier = Modifier
+ .fillMaxSize()
+ .graphicsLayer { alpha = acceptAlpha }
+ .scale(buttonScale)
+ .clip(CircleShape)
+ .background(Color(0xFF4CAF50))
+ ) {
+ Icon(
+ imageVector = Icons.Filled.Call,
+ contentDescription = "Accept",
+ tint = Color.White.copy(alpha = pulseAlpha),
+ modifier = Modifier.size(28.dp)
+ )
+ }
+
+ callerPhoto?.let { photo ->
+ IconButton(
+ onClick = {
+ btnPressed = true
+ onAccept()
+ isDismissing = true
+ },
+ modifier = Modifier
+ .fillMaxSize()
+ .graphicsLayer { alpha = photoAlpha }
+ .scale(buttonScale)
+ .clip(CircleShape)
+ ) {
+ Image(
+ bitmap = photo,
+ contentDescription = "Caller photo",
+ contentScale = ContentScale.Crop,
+ modifier = Modifier
+ .fillMaxSize()
+ .clip(CircleShape)
+ )
+ }
+ }
+ }
+
+ Box(
+ modifier = Modifier
+ .size(32.dp)
+ .clip(CircleShape)
+ .background(MaterialTheme.colorScheme.surfaceContainerHigh)
+ .clickable {
+ isDismissing = true
+ onDismiss()
+ },
+ contentAlignment = Alignment.Center
+ ) {
+ Icon(
+ imageVector = Icons.Filled.KeyboardArrowDown,
+ contentDescription = "Dismiss",
+ tint = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.size(20.dp)
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/DanmakuService.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/DanmakuService.kt
new file mode 100644
index 00000000..999d6a45
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/DanmakuService.kt
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2020 The exTHmUI Open Source Project
+ * Copyright (C) 2021 AOSP-Krypton Project
+ * Copyright (C) 2022 Nameless-AOSP Project
+ * Copyright (C) 2023 the risingOS android Project
+ * Copyright (C) 2022-2024 crDroid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.chaldeaprjkt.gamespace.gamebar
+
+import android.animation.ValueAnimator
+import android.app.Notification
+import android.content.ComponentName
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Color
+import android.graphics.PixelFormat
+import android.os.Handler
+import android.os.Looper
+import android.os.RemoteException
+import android.os.UserHandle
+import android.service.notification.NotificationListenerService
+import android.service.notification.StatusBarNotification
+import android.util.Log
+import android.util.TypedValue
+import android.view.Gravity
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams
+import android.widget.TextView
+
+import androidx.core.animation.addListener
+
+import dagger.hilt.android.qualifiers.ApplicationContext
+import dagger.hilt.android.scopes.ServiceScoped
+
+import java.util.LinkedList
+
+import javax.inject.Inject
+
+import io.chaldeaprjkt.gamespace.R
+import io.chaldeaprjkt.gamespace.data.AppSettings
+import io.chaldeaprjkt.gamespace.gamebar.DanmakuServiceListener
+
+interface DanmakuServiceInterface {
+ val danmakuNotificationMode: Boolean
+ fun showNotificationAsOverlay(danmakuText: String)
+ fun getApplabel(packageName: String): String
+}
+
+@ServiceScoped
+class DanmakuService @Inject constructor(
+ @ApplicationContext private val context: Context,
+ private val appSettings: AppSettings
+) : DanmakuServiceInterface {
+
+ private lateinit var notificationListener: DanmakuServiceListener
+
+ private val notificationOverlay = TextView(context).apply {
+ gravity = Gravity.CENTER
+ maxLines = 2
+ setTextColor(Color.WHITE)
+ isFocusable = false
+ isClickable = false
+ }
+
+ private val windowManager: WindowManager = context.getSystemService(WindowManager::class.java)!!
+
+ private val handler = Handler(Looper.getMainLooper())
+
+ private val notificationStack = LinkedList()
+
+ private var layoutParams: LayoutParams = LayoutParams().apply {
+ height = LayoutParams.WRAP_CONTENT
+ flags = flags or LayoutParams.FLAG_NOT_FOCUSABLE or
+ LayoutParams.FLAG_NOT_TOUCHABLE or
+ LayoutParams.FLAG_HARDWARE_ACCELERATED
+ type = LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY
+ format = PixelFormat.TRANSLUCENT
+ gravity = Gravity.TOP
+ }
+
+ private var isPortrait: Boolean =
+ context.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
+
+ private var verticalOffsetLandscape = 0
+ private var verticalOffsetPortrait = 0
+
+ private var overlayAlphaAnimator: ValueAnimator? = null
+ private var overlayPositionAnimator: ValueAnimator? = null
+
+ fun init() {
+ notificationListener = DanmakuServiceListener()
+ notificationListener.danmakuServiceInterface = this
+ updateParams()
+ registerListener()
+ }
+
+ fun updateConfiguration(newConfig: Configuration) {
+ isPortrait = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+ overlayAlphaAnimator?.end()
+ overlayPositionAnimator?.end()
+ updateParams()
+ updateViewLayoutSafely(layoutParams)
+ }
+
+ fun destroy() {
+ unregisterListener()
+ overlayAlphaAnimator?.cancel()
+ overlayPositionAnimator?.cancel()
+ removeViewSafely()
+ }
+
+ private fun registerListener() {
+ val componentName = ComponentName(context, DanmakuService::class.java)
+ try {
+ notificationListener.registerAsSystemService(
+ context,
+ componentName,
+ UserHandle.USER_CURRENT
+ )
+ } catch (e: RemoteException) {
+ Log.e(TAG, "RemoteException while registering danmaku service")
+ }
+ }
+
+ private fun unregisterListener() {
+ try {
+ notificationListener.unregisterAsSystemService()
+ } catch (e: RemoteException) {
+ Log.e(TAG, "RemoteException while registering danmaku service")
+ }
+ }
+
+ private fun updateParams() {
+ with(context.resources) {
+ verticalOffsetLandscape =
+ getDimensionPixelSize(R.dimen.notification_vertical_offset_landscape)
+ verticalOffsetPortrait =
+ getDimensionPixelSize(R.dimen.notification_vertical_offset_portrait)
+ }
+ layoutParams.y = getOffsetForPosition()
+ layoutParams.width = (NOTIFICATION_MAX_WIDTH * windowManager.currentWindowMetrics.bounds.width()) / 100
+ notificationOverlay.setTextSize(
+ TypedValue.COMPLEX_UNIT_PX,
+ (if (isPortrait) NOTIFICATION_SIZE_PORTRAIT else NOTIFICATION_SIZE_LANDSCAPE).toFloat()
+ )
+ }
+
+ private fun getOffsetForPosition(): Int {
+ return if (isPortrait) verticalOffsetPortrait else verticalOffsetLandscape
+ }
+
+ override fun showNotificationAsOverlay(notification: String) {
+ if (notificationOverlay.parent == null) {
+ notificationOverlay.alpha = 0f
+ notificationOverlay.text = notification
+ windowManager.addView(notificationOverlay, layoutParams)
+ pushNotification()
+ } else {
+ notificationStack.add(notification)
+ }
+ }
+
+ override fun getApplabel(packageName: String): String {
+ return packageName.let {
+ try {
+ val appInfo = context.packageManager.getApplicationInfo(it, 0)
+ context.packageManager.getApplicationLabel(appInfo).toString()
+ } catch (e: Exception) {
+ ""
+ }
+ }
+ }
+
+ override val danmakuNotificationMode: Boolean
+ get() = appSettings.danmakuNotification
+
+ private fun pushNotification() {
+ val end = getOffsetForPosition().toFloat()
+ val start = end * (1 - SLIDE_ANIMATION_DISTANCE_FACTOR)
+ overlayPositionAnimator = getPositionAnimator(APPEAR_ANIMATION_DURATION, start, end).also {
+ it.addListener(onEnd = {
+ handler.postDelayed({
+ popNotification()
+ }, DISPLAY_NOTIFICATION_DURATION)
+ })
+ it.start()
+ }
+ startAlphaAnimation(APPEAR_ANIMATION_DURATION, 0f, 1f)
+ }
+
+ private fun popNotification() {
+ val start = getOffsetForPosition().toFloat()
+ val end = start * (1 + SLIDE_ANIMATION_DISTANCE_FACTOR)
+ overlayPositionAnimator =
+ getPositionAnimator(DISAPPEAR_ANIMATION_DURATION, start, end).also {
+ it.addListener(onEnd = {
+ if (notificationStack.isEmpty()) {
+ removeViewSafely()
+ } else {
+ notificationOverlay.alpha = 0f
+ notificationOverlay.text = notificationStack.pop()
+ pushNotification()
+ }
+ })
+ it.start()
+ }
+ startAlphaAnimation(DISAPPEAR_ANIMATION_DURATION, 1f, 0f)
+ }
+
+ private fun getPositionAnimator(duration: Long, vararg values: Float): ValueAnimator {
+ val lpCopy = LayoutParams().also { it.copyFrom(layoutParams) }
+ return ValueAnimator.ofFloat(*values).apply {
+ this.duration = duration
+ addUpdateListener {
+ lpCopy.y = (it.animatedValue as Float).toInt()
+ updateViewLayoutSafely(lpCopy)
+ }
+ }
+ }
+
+ private fun startAlphaAnimation(duration: Long, vararg values: Float) {
+ overlayAlphaAnimator = ValueAnimator.ofFloat(*values).apply {
+ this.duration = duration
+ addUpdateListener {
+ notificationOverlay.alpha = it.animatedValue as Float
+ }
+ }.also { it.start() }
+ }
+
+ private fun updateViewLayoutSafely(layoutParams: LayoutParams) {
+ if (notificationOverlay.parent != null)
+ windowManager.updateViewLayout(notificationOverlay, layoutParams)
+ }
+
+ private fun removeViewSafely() {
+ if (notificationOverlay.parent != null)
+ windowManager.removeViewImmediate(notificationOverlay)
+ }
+
+ companion object {
+ private const val TAG = "DanmakuService"
+
+ private const val SLIDE_ANIMATION_DISTANCE_FACTOR = 0.5f
+
+ private const val APPEAR_ANIMATION_DURATION = 500L
+ private const val DISPLAY_NOTIFICATION_DURATION = 2000L
+ private const val DISAPPEAR_ANIMATION_DURATION = 300L
+
+ private const val NOTIFICATION_SIZE_LANDSCAPE = 60
+ private const val NOTIFICATION_SIZE_PORTRAIT = 60
+
+ private const val NOTIFICATION_MAX_WIDTH = 75
+
+ private const val NOTIFICATIONS_MAX_CACHED = 99
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/DanmakuServiceListener.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/DanmakuServiceListener.kt
new file mode 100644
index 00000000..40faa29c
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/DanmakuServiceListener.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The exTHmUI Open Source Project
+ * Copyright (C) 2021 AOSP-Krypton Project
+ * Copyright (C) 2022 Nameless-AOSP Project
+ * Copyright (C) 2023 the risingOS android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.chaldeaprjkt.gamespace.gamebar
+
+import android.app.Notification
+import android.service.notification.NotificationListenerService
+import android.service.notification.StatusBarNotification
+
+class DanmakuServiceListener : NotificationListenerService() {
+
+ private val postedNotifications = mutableMapOf()
+
+ private val appLabelsCache = mutableMapOf()
+
+ var danmakuServiceInterface: DanmakuServiceInterface? = null
+
+ override fun onListenerConnected() {
+ super.onListenerConnected()
+ getActiveNotifications()?.forEach { sbn ->
+ if (sbn.isClearable && !sbn.isOngoing) {
+ val danmakuText = extractDanmakuText(sbn)
+ if (danmakuText.isNotBlank()) {
+ postedNotifications[danmakuText] = System.currentTimeMillis()
+ }
+ }
+ }
+ }
+
+ override fun onNotificationPosted(sbn: StatusBarNotification) {
+ val notificationMode = danmakuServiceInterface?.danmakuNotificationMode ?: return
+ if (!notificationMode || !sbn.isClearable || sbn.isOngoing || sbn.getIsContentSecure()) return
+
+ val danmakuText = extractDanmakuText(sbn)
+
+ if (danmakuText.isNotBlank()) {
+ if (!postedNotifications.containsKey(danmakuText)) {
+ postedNotifications[danmakuText] = System.currentTimeMillis()
+ danmakuServiceInterface?.showNotificationAsOverlay(danmakuText)
+ }
+ }
+ }
+
+ override fun onNotificationRemoved(sbn: StatusBarNotification) {
+ val danmakuText = extractDanmakuText(sbn)
+ if (danmakuText.isNotBlank()) {
+ postedNotifications.remove(danmakuText)
+ }
+ }
+
+ private fun extractDanmakuText(sbn: StatusBarNotification): String {
+ val extras = sbn.notification.extras
+ val title = extras.getCharSequence(Notification.EXTRA_TITLE)?.toString()
+ ?: extras.getCharSequence(Notification.EXTRA_TITLE_BIG)?.toString()
+ val text = extras.getCharSequence(Notification.EXTRA_TEXT)?.toString()
+
+ val appLabel = appLabelsCache.getOrPut(sbn.packageName) {
+ danmakuServiceInterface?.getApplabel(sbn.packageName)
+ } ?: ""
+
+ // Skip annoying notification headers
+ if (!title.isNullOrBlank() && !appLabel.isNullOrBlank()) {
+ if (sbn.isGroup && title.contains(appLabel, ignoreCase = true)) return ""
+ }
+
+ return buildDanmakuText(title, text)
+ }
+
+ private fun buildDanmakuText(title: String?, text: String?): String {
+ val sb = StringBuilder()
+ if (!title.isNullOrBlank()) {
+ sb.append("[").append(title).append("]")
+ }
+ if (!text.isNullOrBlank()) {
+ if (sb.isNotEmpty()) sb.append(" ")
+ sb.append(text)
+ }
+ return sb.toString().trim()
+ }
+
+ companion object {
+ private const val NOTIFICATIONS_MAX_CACHED = 99
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/GameBarService.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/GameBarService.kt
index 63ed3cfc..5bea23cf 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/GameBarService.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/GameBarService.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022-2024 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,127 +24,145 @@ import android.graphics.Point
import android.os.Binder
import android.os.Handler
import android.os.Looper
-import android.view.Gravity
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.view.WindowManager
+import android.view.*
import android.widget.FrameLayout
import android.widget.ImageButton
import android.widget.LinearLayout
-import androidx.core.view.children
-import androidx.core.view.isVisible
-import androidx.core.view.marginStart
-import androidx.core.view.updateMargins
-import androidx.core.view.updatePadding
+import androidx.core.view.*
import com.android.systemui.screenrecord.IRecordingCallback
import dagger.hilt.android.AndroidEntryPoint
import io.chaldeaprjkt.gamespace.R
import io.chaldeaprjkt.gamespace.data.AppSettings
-import io.chaldeaprjkt.gamespace.utils.ScreenUtils
-import io.chaldeaprjkt.gamespace.utils.dp
-import io.chaldeaprjkt.gamespace.utils.registerDraggableTouchListener
-import io.chaldeaprjkt.gamespace.utils.statusbarHeight
+import io.chaldeaprjkt.gamespace.data.GameOptimizationManager
+import io.chaldeaprjkt.gamespace.settings.SettingsActivity
+import io.chaldeaprjkt.gamespace.utils.*
import io.chaldeaprjkt.gamespace.widget.MenuSwitcher
import io.chaldeaprjkt.gamespace.widget.PanelView
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.launch
import javax.inject.Inject
-import kotlin.math.max
-import kotlin.math.min
+import kotlin.reflect.KProperty0
@AndroidEntryPoint(Service::class)
class GameBarService : Hilt_GameBarService() {
- @Inject
- lateinit var appSettings: AppSettings
+
+ @Inject lateinit var appSettings: AppSettings
+ @Inject lateinit var screenUtils: ScreenUtils
+ @Inject lateinit var danmakuService: DanmakuService
@Inject
- lateinit var screenUtils: ScreenUtils
+ lateinit var gameOptimization: GameOptimizationManager
- private val scope = CoroutineScope(Job() + Dispatchers.Main)
private val wm by lazy { getSystemService(WINDOW_SERVICE) as WindowManager }
private val handler by lazy { Handler(Looper.getMainLooper()) }
+ private val inflater by lazy { LayoutInflater.from(this) }
+
+ private var halfWidth = 0
+ private var safeHeight = 0
+ private var safeArea = 0
+
+ private val barLayoutParam = WindowManager.LayoutParams(
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ PixelFormat.TRANSLUCENT
+ ).apply {
+ width = WindowManager.LayoutParams.WRAP_CONTENT
+ height = WindowManager.LayoutParams.WRAP_CONTENT
+ layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ preferMinimalPostProcessing = true
+ gravity = Gravity.TOP
+ }
- private val barLayoutParam =
- WindowManager.LayoutParams(
- WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
- PixelFormat.TRANSLUCENT
- ).apply {
- width = WindowManager.LayoutParams.WRAP_CONTENT
- height = WindowManager.LayoutParams.WRAP_CONTENT
- layoutInDisplayCutoutMode =
- WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
- preferMinimalPostProcessing = true
- gravity = Gravity.TOP
- }
-
- private val panelLayoutParam =
- WindowManager.LayoutParams(
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- or WindowManager.LayoutParams.FLAG_DIM_BEHIND,
- PixelFormat.TRANSLUCENT
- ).apply {
- dimAmount = 0.7f
- width = WindowManager.LayoutParams.MATCH_PARENT
- height = WindowManager.LayoutParams.MATCH_PARENT
- layoutInDisplayCutoutMode =
- WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
- gravity = Gravity.CENTER_VERTICAL
-
- }
+ private val panelLayoutParam = WindowManager.LayoutParams(
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
+ WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or
+ WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
+ PixelFormat.TRANSLUCENT
+ ).apply {
+ width = WindowManager.LayoutParams.MATCH_PARENT
+ height = WindowManager.LayoutParams.MATCH_PARENT
+ layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ gravity = Gravity.CENTER_VERTICAL
+ }
private lateinit var rootBarView: View
private lateinit var barView: LinearLayout
private lateinit var menuSwitcher: MenuSwitcher
private lateinit var rootPanelView: LinearLayout
private lateinit var panelView: PanelView
+
private val binder = GameBarBinder()
private val firstPaint = Runnable { initActions() }
- private var barExpanded: Boolean = false
+ private var shouldClose = false
+ private var isGameStarting = false
+
+ private var barExpanded = false
set(value) {
field = value
menuSwitcher.updateIconState(value, barLayoutParam.x)
- barView.children.forEach {
- if (it.id != R.id.action_menu_switcher) {
- it.isVisible = value
- }
- }
+ barView.children.forEach { if (it.id != R.id.action_menu_switcher) it.isVisible = value }
updateBackground()
updateContainerGaps()
}
- private var showPanel: Boolean = false
+ private var showPanel = false
set(value) {
field = value
- if (value && !::rootPanelView.isInitialized || !rootPanelView.isAttachedToWindow) {
- setupPanelView()
- wm.addView(rootPanelView, panelLayoutParam)
- } else if (!value && ::rootPanelView.isInitialized && rootPanelView.isAttachedToWindow) {
- wm.removeView(rootPanelView)
+ if (value) {
+ if (!::rootPanelView.isInitialized) {
+ setupPanelView()
+ }
+ if (!rootPanelView.isAttachedToWindow) {
+ wm.addView(rootPanelView, panelLayoutParam)
+ rootPanelView.fadeIn()
+ }
+ } else {
+ if (safeAttached(::rootPanelView.isInitialized, rootPanelView)) {
+ rootPanelView.fadeOut {
+ rootPanelView.visibility = View.INVISIBLE
+ handler.postDelayed({
+ runCatching {
+ wm.removeView(rootPanelView)
+ }.onFailure { it.printStackTrace() }
+ }, 50)
+ }
+ }
}
}
override fun onCreate() {
super.onCreate()
val frame = FrameLayout(this)
- rootBarView = LayoutInflater.from(this)
- .inflate(R.layout.window_util, frame, false)
+ rootBarView = inflater.inflate(R.layout.window_util, frame, false)
barView = rootBarView.findViewById(R.id.container_bar)
menuSwitcher = rootBarView.findViewById(R.id.action_menu_switcher)
+ applyOpacity()
+ updateScreenMetrics()
+ danmakuService.init()
+ }
+
+ private fun updateScreenMetrics() {
+ val bounds = wm.maximumWindowMetrics.bounds
+ halfWidth = bounds.width() / 2
+ safeArea = statusbarHeight + 4.dp
+ safeHeight = bounds.height() - safeArea
+ }
+
+ private fun applyOpacity() {
+ val alphaValue = appSettings.menuOpacity / 100f
+ barView.alpha = alphaValue
+ menuSwitcher.alpha = alphaValue
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- super.onStartCommand(intent, flags, startId)
when (intent?.action) {
- ACTION_STOP -> onActionStop()
- ACTION_START -> onActionStart()
+ ACTION_STOP -> onGameLeave()
+ ACTION_START -> onGameStart()
+ }
+ intent?.getStringExtra("package")?.let { packageName ->
+ // Apply game optimizations when game starts
+ gameOptimization.optimizeGameLaunch(packageName)
}
return START_STICKY
}
@@ -155,12 +174,14 @@ class GameBarService : Hilt_GameBarService() {
}
override fun onDestroy() {
- onActionStop()
+ onGameLeave()
+ danmakuService.destroy()
super.onDestroy()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
+ updateScreenMetrics()
if (!rootBarView.isVisible) {
handler.removeCallbacks(firstPaint)
handler.postDelayed({
@@ -170,89 +191,101 @@ class GameBarService : Hilt_GameBarService() {
} else {
dockCollapsedMenu()
}
+ danmakuService.updateConfiguration(newConfig)
}
- // for client service
- fun onGameStart() = scope.launch { onActionStart() }
- fun onGameLeave() = scope.launch { onActionStop() }
+ fun onGameStart() {
+ if (isGameStarting) return
+ isGameStarting = true
+
+ handler.post {
+ if (!::rootBarView.isInitialized) return@post
+ if (safeAttached(::rootBarView.isInitialized, rootBarView)) {
+ isGameStarting = false
+ return@post
+ }
- private fun onActionStart() {
- rootBarView.isVisible = false
- rootBarView.alpha = 0f
- if (!rootBarView.isAttachedToWindow) {
+ shouldClose = false
+ rootBarView.isVisible = false
+ rootBarView.alpha = 0f
wm.addView(rootBarView, barLayoutParam)
+ handler.postDelayed(firstPaint, 500)
+ isGameStarting = false
}
- handler.postDelayed(firstPaint, 500)
}
- private fun onActionStop() {
- if (::rootPanelView.isInitialized && rootPanelView.isAttachedToWindow) {
- wm.removeViewImmediate(rootPanelView)
+ fun onGameLeave() {
+ shouldClose = true
+ handler.removeCallbacksAndMessages(null)
+
+ runCatching {
+ if (safeAttached(::rootPanelView.isInitialized, rootPanelView)) {
+ wm.removeViewImmediate(rootPanelView)
+ }
}
- if (rootBarView.isAttachedToWindow) {
- wm.removeViewImmediate(rootBarView)
+
+ runCatching {
+ if (safeAttached(::rootBarView.isInitialized, rootBarView)) {
+ wm.removeViewImmediate(rootBarView)
+ }
}
+
+ stopForeground(true)
+ stopSelf()
}
- private fun updateLayout(with: (WindowManager.LayoutParams) -> Unit = {}) {
+ private fun updateLayout(update: WindowManager.LayoutParams.() -> Unit = {}) {
+ barLayoutParam.update()
if (rootBarView.isAttachedToWindow) {
- wm.updateViewLayout(rootBarView, barLayoutParam.apply(with))
+ wm.updateViewLayout(rootBarView, barLayoutParam)
}
}
private fun initActions() {
- rootBarView.isVisible = true
- rootBarView.animate()
- .alpha(1f)
- .apply { duration = 300 }
- .start()
+ if (shouldClose) return
+ rootBarView.fadeIn()
barExpanded = false
barLayoutParam.x = appSettings.x
barLayoutParam.y = appSettings.y
dockCollapsedMenu()
-
menuSwitcherButton()
panelButton()
screenshotButton()
recorderButton()
}
- private fun onBarDragged(dragged: Boolean) {
- menuSwitcher.isDragged = dragged
- if (dragged) {
- barView.translationX = 0f
- }
- updateBackground()
- }
-
private fun updateBackground() {
val barDragged = !barExpanded && barView.translationX == 0f
val collapsedAtStart = !barDragged && barLayoutParam.x < 0
val collapsedAtEnd = !barDragged && barLayoutParam.x > 0
barView.setBackgroundResource(
when {
- barExpanded -> R.drawable.bar_expanded
+ barExpanded -> R.drawable.bar_normal
collapsedAtStart -> R.drawable.bar_collapsed_start
collapsedAtEnd -> R.drawable.bar_collapsed_end
- else -> R.drawable.bar_dragged
+ else -> R.drawable.bar_normal
}
)
}
private fun updateContainerGaps() {
- if (barExpanded) {
- barView.updatePadding(8, 8, 8, 8)
- (barView.layoutParams as ViewGroup.MarginLayoutParams)
- .updateMargins(right = 48, left = 48)
- } else {
- barView.updatePadding(0, 0, 0, 0)
- (barView.layoutParams as ViewGroup.MarginLayoutParams)
- .updateMargins(right = 0, left = 0)
+ val currentParams = barView.layoutParams as ViewGroup.MarginLayoutParams
+ val targetLeft = if (barExpanded) 48 else 0
+ val targetRight = if (barExpanded) 48 else 0
+
+ if (currentParams.leftMargin != targetLeft || currentParams.rightMargin != targetRight) {
+ barView.updatePaddingRelative(
+ start = if (barExpanded) 8 else 0,
+ top = if (barExpanded) 8 else 0,
+ end = if (barExpanded) 8 else 0,
+ bottom = if (barExpanded) 8 else 0
+ )
+ currentParams.setMargins(targetLeft, 0, targetRight, 0)
+ barView.layoutParams = currentParams
}
}
private fun dockCollapsedMenu() {
- val halfWidth = wm.maximumWindowMetrics.bounds.width() / 2
if (barLayoutParam.x < 0) {
barView.translationX = -22f
barLayoutParam.x = -halfWidth
@@ -261,25 +294,26 @@ class GameBarService : Hilt_GameBarService() {
barLayoutParam.x = halfWidth
}
-
- val safeArea = statusbarHeight + 4.dp
- val safeHeight = wm.maximumWindowMetrics.bounds.height() - safeArea
- barLayoutParam.y = max(min(barLayoutParam.y, safeHeight), safeArea)
-
+ barLayoutParam.y = barLayoutParam.y.coerceIn(safeArea, safeHeight)
updateBackground()
updateContainerGaps()
- updateLayout()
menuSwitcher.showFps = if (barExpanded) false else appSettings.showFps
menuSwitcher.updateIconState(barExpanded, barLayoutParam.x)
+ if (safeAttached(::rootBarView.isInitialized, rootBarView)) {
+ wm.updateViewLayout(rootBarView, barLayoutParam)
+ }
}
private fun setupPanelView() {
- rootPanelView = LayoutInflater.from(this)
- .inflate(R.layout.window_panel, FrameLayout(this), false) as LinearLayout
+ rootPanelView = inflater.inflate(R.layout.window_panel, FrameLayout(this), false) as LinearLayout
+ rootPanelView.alpha = 0f
+ rootPanelView.visibility = View.INVISIBLE
+
panelView = rootPanelView.findViewById(R.id.panel_view)
- rootPanelView.setOnClickListener {
- showPanel = false
- }
+ panelView.alpha = appSettings.menuOpacity / 100f
+
+ rootPanelView.setOnClickListener { showPanel = false }
+
val barWidth = barView.width + barView.marginStart
if (barLayoutParam.x < 0) {
rootPanelView.gravity = Gravity.START
@@ -288,23 +322,21 @@ class GameBarService : Hilt_GameBarService() {
rootPanelView.gravity = Gravity.END
rootPanelView.setPaddingRelative(16, 16, barWidth, 16)
}
- panelView.relativeY = barView.locationOnScreen.last() - barView.height
+ panelView.relativeY = barView.locationOnScreen.last() - barView.height
}
private fun takeShot() {
- val afterShot: () -> Unit = {
+ val afterShot = {
barExpanded = false
- handler.postDelayed({
- updateLayout { it.alpha = 1f }
- }, 100)
+ handler.postDelayed({ updateLayout { alpha = 1f } }, 100)
}
- updateLayout { it.alpha = 0f }
+ updateLayout { alpha = 0f }
handler.postDelayed({
- try {
+ runCatching {
screenUtils.takeScreenshot { afterShot() }
- } catch (e: Exception) {
- e.printStackTrace()
+ }.onFailure {
+ it.printStackTrace()
afterShot()
}
}, 250)
@@ -314,17 +346,24 @@ class GameBarService : Hilt_GameBarService() {
menuSwitcher.setOnClickListener {
barExpanded = !barExpanded
}
+
menuSwitcher.registerDraggableTouchListener(
initPoint = { Point(barLayoutParam.x, barLayoutParam.y) },
listener = { x, y ->
- onBarDragged(true)
- barLayoutParam.x = x
- barLayoutParam.y = y
- updateLayout()
+ if (!menuSwitcher.isDragged) {
+ menuSwitcher.isDragged = true
+ barView.translationX = 0f
+ }
+ updateLayout {
+ this.x = x
+ this.y = y
+ }
+ updateBackground()
},
onComplete = {
- onBarDragged(false)
+ menuSwitcher.isDragged = false
dockCollapsedMenu()
+ updateBackground()
appSettings.x = barLayoutParam.x
appSettings.y = barLayoutParam.y
}
@@ -333,47 +372,67 @@ class GameBarService : Hilt_GameBarService() {
private fun panelButton() {
val actionPanel = rootBarView.findViewById(R.id.action_panel)
- actionPanel.setOnClickListener {
- showPanel = !showPanel
+ actionPanel.alpha = appSettings.menuOpacity / 100f
+ actionPanel.setOnClickListener { showPanel = !showPanel }
+ actionPanel.setOnLongClickListener {
+ startActivity(Intent(this, SettingsActivity::class.java).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
+ true
}
}
private fun screenshotButton() {
- val actionScreenshot = rootBarView.findViewById(R.id.action_screenshot)
- actionScreenshot.setOnClickListener {
- takeShot()
+ rootBarView.findViewById(R.id.action_screenshot).apply {
+ alpha = appSettings.menuOpacity / 100f
+ setOnClickListener { takeShot() }
}
}
private fun recorderButton() {
val actionRecorder = rootBarView.findViewById(R.id.action_record)
- val recorder = screenUtils.recorder ?: let { actionRecorder.isVisible = false; return }
+ actionRecorder.alpha = appSettings.menuOpacity / 100f
+ val recorder = screenUtils.recorder ?: run {
+ actionRecorder.isVisible = false
+ return
+ }
+
recorder.addRecordingCallback(object : IRecordingCallback.Stub() {
override fun onRecordingStart() {
- handler.post {
- actionRecorder.isSelected = true
- }
+ handler.post { actionRecorder.isSelected = true }
}
override fun onRecordingEnd() {
- handler.post {
- actionRecorder.isSelected = false
- }
+ handler.post { actionRecorder.isSelected = false }
}
})
+
actionRecorder.setOnClickListener {
- if (recorder.isStarting) {
- return@setOnClickListener
- }
+ if (recorder.isStarting) return@setOnClickListener
+ if (!recorder.isRecording) recorder.startRecording() else recorder.stopRecording()
+ barExpanded = false
+ }
+ }
- if (!recorder.isRecording) {
- recorder.startRecording()
- } else {
- recorder.stopRecording()
- }
+ fun View.fadeIn(duration: Long = 300L) {
+ if (!isVisible || alpha < 1f) {
+ alpha = 0f
+ isVisible = true
+ animate().alpha(1f).setDuration(duration).start()
+ }
+ }
- barExpanded = false
+ fun View.fadeOut(duration: Long = 300L, endAction: () -> Unit = {}) {
+ if (isVisible && alpha > 0f) {
+ animate().alpha(0f).setDuration(duration).withEndAction(endAction).start()
+ } else {
+ endAction()
+ }
+ }
+
+ fun safeAttached(initialized: Boolean, view: T): Boolean {
+ if (!initialized) {
+ return false
}
+ return view.isAttachedToWindow
}
companion object {
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/GameBroadcastReceiver.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/GameBroadcastReceiver.kt
index 52143264..8b0a4ca1 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/GameBroadcastReceiver.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/GameBroadcastReceiver.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022-2024 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,29 +19,35 @@ package io.chaldeaprjkt.gamespace.gamebar
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
import android.os.Handler
import android.os.Looper
import android.os.UserHandle
-
class GameBroadcastReceiver : BroadcastReceiver() {
+
private val handler by lazy { Handler(Looper.getMainLooper()) }
+
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
GAME_START -> context.onGameStart(intent)
- GAME_STOP -> context.onGameStop(intent)
+ GAME_STOP -> context.onGameStop()
}
}
private fun Context.onGameStart(intent: Intent) {
- handler.post { resendBroadcast(intent) }
- val app = intent.getStringExtra(SessionService.EXTRA_PACKAGE_NAME)
- SessionService.start(this, app)
+ val app = intent.getStringExtra(SessionService.EXTRA_PACKAGE_NAME) ?: return
+ handler.post {
+ resendBroadcast(intent)
+ SessionService.start(this, app)
+ }
}
- private fun Context.onGameStop(intent: Intent) {
- handler.post { resendBroadcast(intent) }
- SessionService.stop(this)
+ private fun Context.onGameStop() {
+ handler.post {
+ resendBroadcast(Intent(GAME_STOP))
+ SessionService.stop(this)
+ }
}
private fun Context.resendBroadcast(prevIntent: Intent) {
@@ -48,13 +55,14 @@ class GameBroadcastReceiver : BroadcastReceiver() {
setPackage(null)
component = null
}
- packageManager.queryBroadcastReceivers(intent, 0)
- ?.mapNotNull { it.activityInfo?.packageName }
- ?.filter { it != packageName }
- ?.forEach {
+ val flags = PackageManager.ResolveInfoFlags.of(0)
+ packageManager.queryBroadcastReceivers(intent, flags)
+ .mapNotNull { it.activityInfo?.packageName }
+ .filter { it != packageName }
+ .forEach {
(intent.clone() as Intent).apply {
setPackage(it)
- sendBroadcastAsUser(this, UserHandle.ALL)
+ sendBroadcastAsUser(this, UserHandle.CURRENT, android.Manifest.permission.MANAGE_GAME_MODE)
}
}
}
@@ -64,4 +72,3 @@ class GameBroadcastReceiver : BroadcastReceiver() {
const val GAME_STOP = "io.chaldeaprjkt.gamespace.action.GAME_STOP"
}
}
-
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/SessionService.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/SessionService.kt
index 7b0f19e5..fd54a21f 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/SessionService.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/SessionService.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022-2024 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +34,7 @@ import io.chaldeaprjkt.gamespace.data.GameSession
import io.chaldeaprjkt.gamespace.data.SystemSettings
import io.chaldeaprjkt.gamespace.utils.GameModeUtils
import io.chaldeaprjkt.gamespace.utils.ScreenUtils
+import io.chaldeaprjkt.gamespace.utils.isServiceRunning
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -56,7 +58,13 @@ class SessionService : Hilt_SessionService() {
@Inject
lateinit var gameModeUtils: GameModeUtils
+ @Inject
+ lateinit var callListener: CallListener
+
private val scope = CoroutineScope(Job() + Dispatchers.IO)
+ private var isRunning = false
+
+ private var tarketPkgName = ""
private val gameBarConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
@@ -71,39 +79,53 @@ class SessionService : Hilt_SessionService() {
}
}
- private lateinit var commandIntent: Intent
private lateinit var gameBar: GameBarService
private lateinit var gameManager: GameManager
private var isBarConnected = false
+ private var commandIntent: Intent? = null
@SuppressLint("WrongConstant")
override fun onCreate() {
super.onCreate()
+ isRunning = true
try {
screenUtils.bind()
} catch (e: RemoteException) {
- Log.d(TAG, e.toString())
+ Log.e(TAG, "Error binding ScreenUtils: $e")
}
gameManager = getSystemService(Context.GAME_SERVICE) as GameManager
gameModeUtils.bind(gameManager)
- isRunning = true
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ if (!isRunning) {
+ Log.w(TAG, "Service is not properly initialized. Stopping.")
+ stopSelf()
+ return START_NOT_STICKY
+ }
+
intent?.let { commandIntent = it }
super.onStartCommand(intent, flags, startId)
+
if (intent == null && flags == 0 && startId > 1) {
return tryStartFromDeath()
}
when (intent?.action) {
START -> startGameBar()
- STOP -> stopSelf()
+ STOP -> {
+ stopSelf()
+ return START_NOT_STICKY
+ }
}
return START_STICKY
}
private fun startGameBar() {
+ if (isBarConnected) {
+ Log.i(TAG, "GameBar is already connected.")
+ return
+ }
Intent(this, GameBarService::class.java).apply {
bindServiceAsUser(this, gameBarConnection, Context.BIND_AUTO_CREATE, UserHandle.CURRENT)
}
@@ -116,46 +138,80 @@ class SessionService : Hilt_SessionService() {
gameBar.onGameLeave()
unbindService(gameBarConnection)
}
+
session.unregister()
gameModeUtils.unbind()
screenUtils.unbind()
+ callListener.destroy()
+
isRunning = false
super.onDestroy()
}
private fun onGameBarReady() {
if (!isBarConnected) {
+ Log.w(TAG, "GameBar is not connected. Retrying connection.")
startGameBar()
return
}
try {
- session.unregister()
- if (!::commandIntent.isInitialized) {
- // something is not right, bailing out
+ commandIntent?.let { intent ->
+ val app = intent.getStringExtra(EXTRA_PACKAGE_NAME) ?: run {
+ Log.e(TAG, "App package name missing in intent. Stopping service.")
+ stopSelf()
+ return
+ }
+ tarketPkgName = app
+ session.unregister()
+ session.register(app)
+ applyGameModeConfig(app)
+ gameBar.onGameStart()
+ screenUtils.stayAwake = appSettings.stayAwake
+ screenUtils.lockGesture = appSettings.lockGesture
+ } ?: run {
+ Log.e(TAG, "Command Intent is uninitialized. Stopping service.")
stopSelf()
}
- val app = commandIntent.getStringExtra(EXTRA_PACKAGE_NAME)
- session.register(app)
- applyGameModeConfig(app)
- gameBar.onGameStart()
- screenUtils.stayAwake = appSettings.stayAwake
+
+ callListener.init()
} catch (e: Exception) {
- Log.d(TAG, e.toString())
+ Log.e(TAG, "Error during GameBar initialization: $e")
+ stopSelf()
}
}
private fun tryStartFromDeath(): Int {
- val game = ActivityTaskManager.getService()
+ if (isBarConnected) {
+ return START_STICKY
+ }
+
+ if (tarketPkgName.isBlank()) {
+ stopSelf()
+ return START_NOT_STICKY
+ }
+
+ val focusedApp = ActivityTaskManager.getService()
?.focusedRootTaskInfo
- ?.topActivity?.packageName
- ?: return START_NOT_STICKY
+ ?.topActivity
+ ?.packageName
- if (!settings.userGames.any { it.packageName == game }) {
+ if (focusedApp.isNullOrBlank()) {
+ stopSelf()
return START_NOT_STICKY
}
- commandIntent = Intent(START).putExtra(EXTRA_PACKAGE_NAME, game)
+ if (!settings.userGames.any { it.packageName == focusedApp }) {
+ stopSelf()
+ return START_NOT_STICKY
+ }
+
+ if (focusedApp != tarketPkgName) {
+ stopSelf()
+ return START_NOT_STICKY
+ }
+
+ commandIntent = Intent(START).putExtra(EXTRA_PACKAGE_NAME, tarketPkgName)
startGameBar()
return START_STICKY
}
@@ -176,20 +232,18 @@ class SessionService : Hilt_SessionService() {
const val START = "game_start"
const val STOP = "game_stop"
const val EXTRA_PACKAGE_NAME = "package_name"
- var isRunning = false
- private set
fun start(context: Context, app: String) = Intent(context, SessionService::class.java)
.apply {
action = START
putExtra(EXTRA_PACKAGE_NAME, app)
}
- .takeIf { !isRunning }
+ .takeIf { !context.isServiceRunning(SessionService::class.java) }
?.run { context.startServiceAsUser(this, UserHandle.CURRENT) }
fun stop(context: Context) = Intent(context, SessionService::class.java)
.apply { action = STOP }
- .takeIf { isRunning }
- ?.run { context.startServiceAsUser(this, UserHandle.CURRENT) }
+ .takeIf { context.isServiceRunning(SessionService::class.java) }
+ ?.run { context.stopServiceAsUser(this, UserHandle.CURRENT) }
}
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/lifecycle/repeatWhenAttached.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/lifecycle/repeatWhenAttached.kt
new file mode 100644
index 00000000..6864447e
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/gamebar/lifecycle/repeatWhenAttached.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2025 AxionOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.chaldeaprjkt.gamespace.gamebar.lifecycle
+
+import android.view.View
+import android.view.ViewTreeObserver
+import androidx.annotation.MainThread
+import androidx.lifecycle.*
+import androidx.savedstate.*
+import kotlinx.coroutines.*
+import kotlin.coroutines.*
+
+@MainThread
+fun View.repeatWhenAttached(
+ block: suspend LifecycleOwner.(View) -> Unit
+): DisposableHandle {
+ val view = this
+ val lifecycleCoroutineContext = Dispatchers.Main + EmptyCoroutineContext
+ var lifecycleOwner: ViewLifecycleOwner? = null
+
+ val onAttachListener = object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View) {
+ lifecycleOwner?.onDestroy()
+ lifecycleOwner = createLifecycleOwnerAndRun(view, lifecycleCoroutineContext, block)
+ }
+
+ override fun onViewDetachedFromWindow(v: View) {
+ lifecycleOwner?.onDestroy()
+ lifecycleOwner = null
+ }
+ }
+
+ addOnAttachStateChangeListener(onAttachListener)
+ if (view.isAttachedToWindow) {
+ lifecycleOwner = createLifecycleOwnerAndRun(view, lifecycleCoroutineContext, block)
+ }
+
+ return DisposableHandle {
+ lifecycleOwner?.onDestroy()
+ lifecycleOwner = null
+ view.removeOnAttachStateChangeListener(onAttachListener)
+ }
+}
+
+private fun createLifecycleOwnerAndRun(
+ view: View,
+ coroutineContext: CoroutineContext,
+ block: suspend LifecycleOwner.(View) -> Unit
+): ViewLifecycleOwner {
+ return ViewLifecycleOwner(view).apply {
+ onCreate()
+ lifecycleScope.launch(context = coroutineContext) { block(view) }
+ }
+}
+
+class ViewLifecycleOwner(private val view: View) : LifecycleOwner {
+ private val registry = LifecycleRegistry(this)
+ private val windowVisibleListener =
+ ViewTreeObserver.OnWindowVisibilityChangeListener { updateState() }
+ private val windowFocusListener =
+ ViewTreeObserver.OnWindowFocusChangeListener { updateState() }
+ private val savedStateRegistryOwner =
+ object : SavedStateRegistryOwner {
+ private val savedStateRegistryController =
+ SavedStateRegistryController.create(this).apply { performRestore(null) }
+ override val savedStateRegistry = savedStateRegistryController.savedStateRegistry
+ override val lifecycle: Lifecycle
+ get() = registry
+ }
+
+ fun onCreate() {
+ registry.currentState = Lifecycle.State.CREATED
+ view.viewTreeObserver.addOnWindowVisibilityChangeListener(windowVisibleListener)
+ view.viewTreeObserver.addOnWindowFocusChangeListener(windowFocusListener)
+ view.setViewTreeLifecycleOwner(this)
+ view.setViewTreeSavedStateRegistryOwner(savedStateRegistryOwner)
+ updateState()
+ }
+
+ fun onDestroy() {
+ view.viewTreeObserver.removeOnWindowVisibilityChangeListener(windowVisibleListener)
+ view.viewTreeObserver.removeOnWindowFocusChangeListener(windowFocusListener)
+ view.setViewTreeLifecycleOwner(null)
+ view.setViewTreeSavedStateRegistryOwner(null)
+ registry.currentState = Lifecycle.State.DESTROYED
+ }
+
+ override val lifecycle: Lifecycle get() = registry
+
+ private fun updateState() {
+ registry.currentState = when {
+ view.windowVisibility != View.VISIBLE -> Lifecycle.State.CREATED
+ !view.hasWindowFocus() -> Lifecycle.State.STARTED
+ else -> Lifecycle.State.RESUMED
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/AppListPreferences.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/AppListPreferences.kt
index 7de8c8c0..f0c85bf3 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/AppListPreferences.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/AppListPreferences.kt
@@ -52,7 +52,7 @@ class AppListPreferences @JvmOverloads constructor(context: Context, attrs: Attr
private val makeAddPref by lazy {
Preference(context).apply {
- title = "Add"
+ title = context.getString(R.string.game_list_add_title)
key = KEY_ADD_GAME
setIcon(R.drawable.ic_add)
isPersistent = false
@@ -61,7 +61,8 @@ class AppListPreferences @JvmOverloads constructor(context: Context, attrs: Attr
}
private fun getAppInfo(packageName: String): ApplicationInfo? = try {
- context.packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
+ val flags = PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
+ context.packageManager.getApplicationInfo(packageName, flags)
} catch (e: PackageManager.NameNotFoundException) {
null
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/QuickStartAppPreference.java b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/QuickStartAppPreference.java
new file mode 100644
index 00000000..8f53f877
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/QuickStartAppPreference.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2023-2024 the risingOS Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.chaldeaprjkt.gamespace.preferences;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import androidx.preference.DialogPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class QuickStartAppPreference extends DialogPreference {
+
+ private String[] appPackageNames;
+ private String[] appNames;
+ private Drawable[] appIcons;
+
+ public QuickStartAppPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ loadInstalledUserApps(context);
+ }
+
+ private void loadInstalledUserApps(Context context) {
+ PackageManager pm = context.getPackageManager();
+ List apps = pm.getInstalledApplications(PackageManager.GET_META_DATA);
+ List packageNames = new ArrayList<>();
+ List names = new ArrayList<>();
+ List icons = new ArrayList<>();
+ for (ApplicationInfo app : apps) {
+ if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ packageNames.add(app.packageName);
+ names.add(pm.getApplicationLabel(app).toString());
+ icons.add(pm.getApplicationIcon(app));
+ }
+ }
+ appPackageNames = packageNames.toArray(new String[0]);
+ appNames = names.toArray(new String[0]);
+ appIcons = icons.toArray(new Drawable[0]);
+ sortAppsAlphabetically();
+ }
+
+ private void sortAppsAlphabetically() {
+ for (int i = 0; i < appNames.length - 1; i++) {
+ for (int j = i + 1; j < appNames.length; j++) {
+ if (appNames[i].compareToIgnoreCase(appNames[j]) > 0) {
+ swapApps(i, j);
+ }
+ }
+ }
+ }
+
+ private void swapApps(int i, int j) {
+ String tempName = appNames[i];
+ Drawable tempIcon = appIcons[i];
+ String tempPackage = appPackageNames[i];
+ appNames[i] = appNames[j];
+ appIcons[i] = appIcons[j];
+ appPackageNames[i] = appPackageNames[j];
+ appNames[j] = tempName;
+ appIcons[j] = tempIcon;
+ appPackageNames[j] = tempPackage;
+ }
+
+ public String[] getAppPackageNames() {
+ return appPackageNames;
+ }
+
+ public String[] getAppNames() {
+ return appNames;
+ }
+
+ public Drawable[] getAppIcons() {
+ return appIcons;
+ }
+
+ public void saveValue(String value) {
+ persistString(value);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/QuickStartAppPreferenceDialogFragment.java b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/QuickStartAppPreferenceDialogFragment.java
new file mode 100644
index 00000000..d33de3f9
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/QuickStartAppPreferenceDialogFragment.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2023-2024 the risingOS Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.chaldeaprjkt.gamespace.preferences;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.View;
+import android.view.Window;
+import android.view.ViewGroup;
+import android.widget.ListView;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.preference.PreferenceDialogFragmentCompat;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+import io.chaldeaprjkt.gamespace.R;
+
+public class QuickStartAppPreferenceDialogFragment extends PreferenceDialogFragmentCompat {
+
+ private Set selectedPackages = new HashSet<>();
+
+ public static QuickStartAppPreferenceDialogFragment newInstance(String key) {
+ final QuickStartAppPreferenceDialogFragment fragment = new QuickStartAppPreferenceDialogFragment();
+ final Bundle b = new Bundle(1);
+ b.putString(ARG_KEY, key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(@NonNull AlertDialog.Builder builder) {
+ super.onPrepareDialogBuilder(builder);
+ QuickStartAppPreference preference = (QuickStartAppPreference) getPreference();
+ Context context = getContext();
+ if (preference == null || context == null) {
+ return;
+ }
+ String savedApps = Settings.System.getString(context.getContentResolver(), "quick_start_apps");
+ if (savedApps != null && !savedApps.isEmpty()) {
+ String[] savedAppsArray = savedApps.split(",");
+ for (String app : savedAppsArray) {
+ selectedPackages.add(app);
+ }
+ }
+ boolean[] checkedItems = new boolean[preference.getAppNames().length];
+ String[] appPackageNames = preference.getAppPackageNames();
+ for (int i = 0; i < appPackageNames.length; i++) {
+ checkedItems[i] = selectedPackages.contains(appPackageNames[i]);
+ }
+ builder.setTitle(R.string.quick_start_apps_title)
+ .setMultiChoiceItems(preference.getAppNames(), checkedItems, new DialogInterface.OnMultiChoiceClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which, boolean isChecked) {
+ String selectedApp = appPackageNames[which];
+ if (isChecked) {
+ selectedPackages.add(selectedApp);
+ } else {
+ selectedPackages.remove(selectedApp);
+ }
+ }
+ })
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ saveSelectedApps(context);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null);
+ }
+
+ @Override
+ public void onDialogClosed(boolean positiveResult) {}
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ final Dialog dialog = getDialog();
+ if (dialog == null) return;
+
+ final Window window = dialog.getWindow();
+ if (window != null) {
+ WindowCompat.setDecorFitsSystemWindows(window, false);
+ final View decor = window.getDecorView();
+ ViewCompat.setOnApplyWindowInsetsListener(decor, (v, insets) -> {
+ Insets bars = insets.getInsets(
+ WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.ime());
+ v.setPadding(bars.left, bars.top, bars.right, bars.bottom);
+ return insets;
+ });
+ }
+
+ final ListView list = dialog.findViewById(android.R.id.list);
+ if (list != null) {
+ list.setClipToPadding(false);
+ list.setPadding(
+ list.getPaddingLeft(),
+ list.getPaddingTop(),
+ list.getPaddingRight(),
+ list.getPaddingBottom() + dp(16) // keeps last row from staying behind buttons
+ );
+
+ list.post(() -> {
+ int screenH = list.getResources().getDisplayMetrics().heightPixels;
+ int max = (int) (screenH * 0.6f); // cap to ~60% of screen
+ if (list.getHeight() > max) {
+ ViewGroup.LayoutParams lp = list.getLayoutParams();
+ lp.height = max;
+ list.setLayoutParams(lp);
+ }
+ });
+ }
+ }
+
+ private int dp(int v) {
+ return Math.round(v * getResources().getDisplayMetrics().density);
+ }
+
+ private void saveSelectedApps(Context context) {
+ String[] selectedArray = selectedPackages.toArray(new String[0]);
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < selectedArray.length; i++) {
+ sb.append(selectedArray[i]);
+
+ if (i < selectedArray.length - 1) {
+ sb.append(",");
+ }
+ }
+ Settings.System.putString(context.getContentResolver(), "quick_start_apps", sb.toString());
+ QuickStartAppPreference preference = (QuickStartAppPreference) getPreference();
+ if (preference != null) {
+ preference.saveValue(sb.toString());
+ }
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/appselector/AppSelectorActivity.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/appselector/AppSelectorActivity.kt
index a4907e69..d6700279 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/appselector/AppSelectorActivity.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/appselector/AppSelectorActivity.kt
@@ -26,7 +26,7 @@ class AppSelectorActivity : Hilt_AppSelectorActivity() {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
supportFragmentManager.beginTransaction()
- .replace(com.android.settingslib.R.id.content_frame, AppSelectorFragment())
+ .replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame, AppSelectorFragment())
.commit()
}
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/appselector/AppSelectorFragment.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/appselector/AppSelectorFragment.kt
index 51ef97b4..27ba55fe 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/appselector/AppSelectorFragment.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/preferences/appselector/AppSelectorFragment.kt
@@ -27,8 +27,10 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.SearchView
+import androidx.core.view.MenuProvider
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
+import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.AppBarLayout
@@ -49,9 +51,17 @@ class AppSelectorFragment : Hilt_AppSelectorFragment(), SearchView.OnQueryTextLi
private var appsAdapter: AppsAdapter? = null
private var appBarLayout: AppBarLayout? = null
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setHasOptionsMenu(true)
+ private val menuProvider = object : MenuProvider {
+ override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+ menuInflater.inflate(R.menu.app_selector_menu, menu)
+ val searchMenuItem = menu.findItem(R.id.app_search_menu)
+ val searchView = searchMenuItem.actionView as? SearchView
+ searchView?.setOnQueryTextListener(this@AppSelectorFragment)
+ searchView?.queryHint = getString(R.string.app_search_title)
+ searchMenuItem.setOnActionExpandListener(this@AppSelectorFragment)
+ }
+
+ override fun onMenuItemSelected(menuItem: MenuItem) = false
}
override fun onCreateView(
@@ -60,31 +70,23 @@ class AppSelectorFragment : Hilt_AppSelectorFragment(), SearchView.OnQueryTextLi
savedInstanceState: Bundle?
): View? {
super.onCreateView(inflater, container, savedInstanceState)
- appBarLayout = activity?.findViewById(com.android.settingslib.R.id.app_bar)
+ appBarLayout = activity?.findViewById(com.android.settingslib.collapsingtoolbar.R.id.app_bar)
return inflater.inflate(R.layout.app_selector, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+ activity?.addMenuProvider(menuProvider, viewLifecycleOwner, Lifecycle.State.RESUMED)
view.findViewById(R.id.app_list)?.apply {
setupAppListView(this)
}
}
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- super.onCreateOptionsMenu(menu, inflater)
- inflater.inflate(R.menu.app_selector_menu, menu)
- val searchMenuItem = menu.findItem(R.id.app_search_menu)
- val searchView = searchMenuItem.actionView as SearchView
- searchView.setOnQueryTextListener(this)
- searchView.queryHint = getString(R.string.app_search_title)
- searchMenuItem.setOnActionExpandListener(this)
- }
-
private fun setupAppListView(view: RecyclerView) {
appListView = view
+ val flags = PackageManager.ApplicationInfoFlags.of(PackageManager.GET_META_DATA.toLong())
val apps = view.context.packageManager
- .getInstalledApplications(PackageManager.GET_META_DATA)
+ .getInstalledApplications(flags)
.filter {
it.packageName != context?.packageName &&
it.flags and ApplicationInfo.FLAG_SYSTEM == 0 &&
@@ -110,13 +112,13 @@ class AppSelectorFragment : Hilt_AppSelectorFragment(), SearchView.OnQueryTextLi
return false
}
- override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
+ override fun onMenuItemActionExpand(item: MenuItem): Boolean {
appBarLayout?.setExpanded(false, false)
appListView?.let { ViewCompat.setNestedScrollingEnabled(it, false) }
return true
}
- override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
+ override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
appBarLayout?.setExpanded(false, false)
appListView?.let { ViewCompat.setNestedScrollingEnabled(it, true) }
return true
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/settings/PerAppSettingsActivity.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/settings/PerAppSettingsActivity.kt
index a0900fe7..625c4e55 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/settings/PerAppSettingsActivity.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/settings/PerAppSettingsActivity.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022-2024 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,7 +20,6 @@ import android.os.Bundle
import android.util.Log
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity
import dagger.hilt.android.AndroidEntryPoint
-import io.chaldeaprjkt.gamespace.utils.assertStarterOrigin
@AndroidEntryPoint(CollapsingToolbarBaseActivity::class)
class PerAppSettingsActivity : Hilt_PerAppSettingsActivity() {
@@ -29,7 +29,7 @@ class PerAppSettingsActivity : Hilt_PerAppSettingsActivity() {
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
- .replace(com.android.settingslib.R.id.content_frame, PerAppSettingsFragment())
+ .replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame, PerAppSettingsFragment())
.commit()
}
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/settings/PerAppSettingsFragment.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/settings/PerAppSettingsFragment.kt
index c86649b1..88cda8da 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/settings/PerAppSettingsFragment.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/settings/PerAppSettingsFragment.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022-2024 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,21 +18,30 @@ package io.chaldeaprjkt.gamespace.settings
import android.app.Activity
import android.content.Intent
+import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+
import androidx.preference.ListPreference
import androidx.preference.Preference
-import androidx.preference.PreferenceFragmentCompat
-import androidx.preference.SwitchPreference
+import androidx.preference.SwitchPreferenceCompat
+
+import com.android.settingslib.widget.LayoutPreference
+import com.android.settingslib.widget.SettingsBasePreferenceFragment
+
import dagger.hilt.android.AndroidEntryPoint
+
import io.chaldeaprjkt.gamespace.R
import io.chaldeaprjkt.gamespace.data.GameConfig
import io.chaldeaprjkt.gamespace.data.SystemSettings
import io.chaldeaprjkt.gamespace.data.UserGame
import io.chaldeaprjkt.gamespace.utils.GameModeUtils
+
import javax.inject.Inject
-@AndroidEntryPoint(PreferenceFragmentCompat::class)
+@AndroidEntryPoint(SettingsBasePreferenceFragment::class)
class PerAppSettingsFragment : Hilt_PerAppSettingsFragment(),
Preference.OnPreferenceChangeListener {
@@ -42,10 +52,10 @@ class PerAppSettingsFragment : Hilt_PerAppSettingsFragment(),
lateinit var gameModeUtils: GameModeUtils
private val currentGame by lazy {
- context?.packageManager?.getApplicationInfo(
- activity?.intent?.getStringExtra(PerAppSettingsActivity.EXTRA_PACKAGE),
- 0
- )
+ activity?.intent?.getStringExtra(PerAppSettingsActivity.EXTRA_PACKAGE)?.let {
+ val flags = PackageManager.ApplicationInfoFlags.of(0)
+ context?.packageManager?.getApplicationInfo(it, flags)
+ }
}
private val currentConfig: UserGame?
@@ -62,17 +72,19 @@ class PerAppSettingsFragment : Hilt_PerAppSettingsFragment(),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
- findPreference("headers")?.apply {
- layoutResource = R.layout.per_app_header
- icon = currentGame?.loadIcon(context?.packageManager)
- title = context?.packageManager?.let { currentGame?.loadLabel(it) }
+ findPreference("headers")?.apply {
+ isSelectable = false
+ findViewById(android.R.id.icon)
+ ?.setImageDrawable(currentGame?.loadIcon(requireContext().packageManager))
+ findViewById(android.R.id.title)
+ ?.text = currentGame?.loadLabel(requireContext().packageManager)
}
findPreference(PREF_PREFERRED_MODE)?.apply {
currentConfig?.mode?.let { value = it.toString() }
onPreferenceChangeListener = this@PerAppSettingsFragment
}
- findPreference(PREF_USE_ANGLE)?.apply {
- context?.resources?.getBoolean(R.bool.config_allow_per_app_angle_usage)?.let {
+ findPreference(PREF_USE_ANGLE)?.apply {
+ context.resources?.getBoolean(R.bool.config_allow_per_app_angle_usage)?.let {
isVisible = it
if (!it) return@apply
}
@@ -89,7 +101,7 @@ class PerAppSettingsFragment : Hilt_PerAppSettingsFragment(),
findPreference(PREF_UNREGISTER)?.apply {
summary = context.getString(
R.string.per_app_unregister,
- currentGame?.loadLabel(context?.packageManager)
+ currentGame?.loadLabel(context.packageManager)
)
setOnPreferenceClickListener {
activity?.setResult(Activity.RESULT_OK, Intent().apply {
@@ -101,9 +113,9 @@ class PerAppSettingsFragment : Hilt_PerAppSettingsFragment(),
}
}
- override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
+ override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
val gameInfo = currentGame ?: return false
- when (preference?.key) {
+ when (preference.key) {
PREF_PREFERRED_MODE -> {
val newMode = (newValue as String).toIntOrNull() ?: 1
gameModeUtils.setGameModeFor(gameInfo.packageName, settings, newMode)
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/settings/SettingsActivity.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/settings/SettingsActivity.kt
index d6738e7a..b97305ad 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/settings/SettingsActivity.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/settings/SettingsActivity.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022-2024 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,18 +19,16 @@ package io.chaldeaprjkt.gamespace.settings
import android.os.Bundle
import com.android.settingslib.collapsingtoolbar.CollapsingToolbarBaseActivity
import dagger.hilt.android.AndroidEntryPoint
-import io.chaldeaprjkt.gamespace.utils.assertStarterOrigin
@AndroidEntryPoint(CollapsingToolbarBaseActivity::class)
class SettingsActivity : Hilt_SettingsActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
- assertStarterOrigin()
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
- .replace(com.android.settingslib.R.id.content_frame, SettingsFragment())
+ .replace(com.android.settingslib.collapsingtoolbar.R.id.content_frame, SettingsFragment())
.commit()
}
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/settings/SettingsFragment.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/settings/SettingsFragment.kt
index 4e4edafb..35b7b2b1 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/settings/SettingsFragment.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/settings/SettingsFragment.kt
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022-2025 crDroid Android Project
+ * 2023-2024 the risingOS Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,19 +23,26 @@ import android.provider.Settings
import android.view.View
import androidx.activity.result.contract.ActivityResultContracts
import androidx.preference.Preference
-import androidx.preference.PreferenceFragmentCompat
-import androidx.preference.SwitchPreference
+import androidx.preference.SwitchPreferenceCompat
+import androidx.preference.ListPreference
+
+import com.android.settingslib.widget.SettingsBasePreferenceFragment
+
import dagger.hilt.android.AndroidEntryPoint
+
import io.chaldeaprjkt.gamespace.R
-import io.chaldeaprjkt.gamespace.data.SystemSettings
+import io.chaldeaprjkt.gamespace.data.GameOptimizationManager
import io.chaldeaprjkt.gamespace.preferences.AppListPreferences
import io.chaldeaprjkt.gamespace.preferences.appselector.AppSelectorActivity
+import io.chaldeaprjkt.gamespace.preferences.QuickStartAppPreference
+import io.chaldeaprjkt.gamespace.preferences.QuickStartAppPreferenceDialogFragment
import javax.inject.Inject
-@AndroidEntryPoint(PreferenceFragmentCompat::class)
+@AndroidEntryPoint(SettingsBasePreferenceFragment::class)
class SettingsFragment : Hilt_SettingsFragment(), Preference.OnPreferenceChangeListener {
+
@Inject
- lateinit var settings: SystemSettings
+ lateinit var gameOptimization: GameOptimizationManager
private var apps: AppListPreferences? = null
@@ -57,6 +66,28 @@ class SettingsFragment : Hilt_SettingsFragment(), Preference.OnPreferenceChangeL
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
+
+ // Game Optimization preferences
+ findPreference("game_launch_boost")?.apply {
+ isChecked = gameOptimization.isLaunchBoostEnabled
+ onPreferenceChangeListener = this@SettingsFragment
+ }
+
+ findPreference("game_memory_management")?.apply {
+ isChecked = gameOptimization.isMemoryManagementEnabled
+ onPreferenceChangeListener = this@SettingsFragment
+ }
+
+ findPreference("game_load_priority")?.apply {
+ value = gameOptimization.loadPriority
+ onPreferenceChangeListener = this@SettingsFragment
+ }
+
+ findPreference("game_cache_management")?.apply {
+ isChecked = gameOptimization.isCacheManagementEnabled
+ onPreferenceChangeListener = this@SettingsFragment
+ }
+
apps = findPreference(Settings.System.GAMESPACE_GAME_LIST)
apps?.onRegisteredAppClick {
perAppResult.launch(Intent(context, PerAppSettingsActivity::class.java).apply {
@@ -69,11 +100,6 @@ class SettingsFragment : Hilt_SettingsFragment(), Preference.OnPreferenceChangeL
selectorResult.launch(Intent(context, AppSelectorActivity::class.java))
return@setOnPreferenceClickListener true
}
-
- findPreference(Settings.System.GAMESPACE_SUPPRESS_FULLSCREEN_INTENT)?.apply {
- isChecked = settings.suppressFullscreenIntent
- onPreferenceChangeListener = this@SettingsFragment
- }
}
override fun onResume() {
@@ -81,10 +107,32 @@ class SettingsFragment : Hilt_SettingsFragment(), Preference.OnPreferenceChangeL
apps?.updateAppList()
}
- override fun onPreferenceChange(preference: Preference?, newValue: Any?): Boolean {
- when (preference?.key) {
- Settings.System.GAMESPACE_SUPPRESS_FULLSCREEN_INTENT -> {
- settings.suppressFullscreenIntent = newValue as Boolean
+ override fun onDisplayPreferenceDialog(preference: Preference) {
+ if (preference is QuickStartAppPreference) {
+ val dialogFragment = QuickStartAppPreferenceDialogFragment.newInstance(preference.key)
+ dialogFragment.setTargetFragment(this, 0)
+ dialogFragment.show(parentFragmentManager, "QuickStartAppPreferenceDialogFragment")
+ } else {
+ super.onDisplayPreferenceDialog(preference)
+ }
+ }
+
+ override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
+ when (preference.key) {
+ "game_launch_boost" -> {
+ gameOptimization.isLaunchBoostEnabled = newValue as Boolean
+ return true
+ }
+ "game_memory_management" -> {
+ gameOptimization.isMemoryManagementEnabled = newValue as Boolean
+ return true
+ }
+ "game_load_priority" -> {
+ gameOptimization.loadPriority = newValue as String
+ return true
+ }
+ "game_cache_management" -> {
+ gameOptimization.isCacheManagementEnabled = newValue as Boolean
return true
}
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/utils/Extensions.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/utils/Extensions.kt
index feb0fb20..8bfe5e37 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/utils/Extensions.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/utils/Extensions.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +17,8 @@
package io.chaldeaprjkt.gamespace.utils
import android.app.Activity
+import android.app.ActivityManager
+import android.app.Service
import android.content.Context
import android.content.res.Resources.getSystem
import android.graphics.Point
@@ -42,9 +45,11 @@ val Int.dp
fun WindowManager.isPortrait() =
maximumWindowMetrics.bounds.width() < maximumWindowMetrics.bounds.height()
-fun Activity.assertStarterOrigin() =
- intent?.getStringExtra("referer")?.takeIf { it.isNotEmpty() }
- ?: throw SecurityException("failed to assert starter origin")
-
inline fun Context.entryPointOf(): T =
EntryPoints.get(applicationContext, T::class.java)
+
+@Suppress("DEPRECATION") // Deprecated for third party services.
+fun Context.isServiceRunning(serviceClass: Class<*>): Boolean =
+ (getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
+ .getRunningServices(Integer.MAX_VALUE)
+ .any { it.service.className == serviceClass.name }
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/utils/GameModeUtils.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/utils/GameModeUtils.kt
index 231fe4ae..5487b195 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/utils/GameModeUtils.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/utils/GameModeUtils.kt
@@ -18,11 +18,13 @@ package io.chaldeaprjkt.gamespace.utils
import android.app.GameManager
import android.content.Context
import android.content.Intent
+import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.os.IDeviceIdleController
import android.os.RemoteException
import android.os.ServiceManager
import android.provider.DeviceConfig
+import android.provider.Settings
import io.chaldeaprjkt.gamespace.R
import io.chaldeaprjkt.gamespace.data.GameConfig
import io.chaldeaprjkt.gamespace.data.GameConfig.Companion.asConfig
@@ -44,8 +46,14 @@ class GameModeUtils @Inject constructor(private val context: Context) {
}
fun setIntervention(packageName: String, modeData: List? = null) {
- DeviceConfig.setProperty(
- DeviceConfig.NAMESPACE_GAME_OVERLAY, packageName, modeData?.asConfig(), false
+ // Separate key and value by ;; to identify them from
+ // com.android.server.app.GameManagerService for the device_config property.
+ // Example: com.libremobileos.game;;mode=2,downscaleFactor=0.7:mode=3,downscaleFactor=0.8
+ val configValue = "${packageName};;${modeData?.asConfig()}"
+ Settings.Secure.putString(
+ context.contentResolver,
+ Settings.Secure.GAME_OVERLAY,
+ configValue
)
}
@@ -81,10 +89,13 @@ class GameModeUtils @Inject constructor(private val context: Context) {
}
}
- fun findAnglePackage() = context.packageManager.queryIntentActivities(
- Intent(ACTION_ANGLE_FOR_ANDROID),
- PackageManager.MATCH_SYSTEM_ONLY
- ).firstOrNull()?.activityInfo
+
+ fun findAnglePackage(): ActivityInfo? {
+ val intent = Intent(ACTION_ANGLE_FOR_ANDROID)
+ val flags = PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_SYSTEM_ONLY.toLong())
+ val info = context.packageManager.queryIntentActivities(intent, flags)
+ return info.firstOrNull()?.activityInfo
+ }
fun isAngleUsed(packageName: String?) = packageName?.let {
DeviceConfig.getString(DeviceConfig.NAMESPACE_GAME_OVERLAY, it, null)
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/utils/ScreenUtils.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/utils/ScreenUtils.kt
index 89c66ae4..62ba5f27 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/utils/ScreenUtils.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/utils/ScreenUtils.kt
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2021 Chaldeaprjkt
+ * 2022 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +27,7 @@ import android.os.IBinder
import android.os.Looper
import android.os.PowerManager
import android.os.UserHandle
+import android.provider.Settings
import android.view.WindowManager
import com.android.internal.util.ScreenshotHelper
import com.android.systemui.screenrecord.IRemoteRecording
@@ -57,6 +59,8 @@ class ScreenUtils @Inject constructor(private val context: Context) {
val recorder: IRemoteRecording? get() = remoteRecording
+ private var isGestureLocked = false
+
fun bind() {
isRecorderBound = context.bindServiceAsUser(Intent().apply {
component = ComponentName(
@@ -78,12 +82,17 @@ class ScreenUtils @Inject constructor(private val context: Context) {
context.unbindService(recorderConnection)
}
remoteRecording = null
+ if (isGestureLocked) {
+ Settings.System.putIntForUser(context.contentResolver,
+ Settings.System.LOCK_GESTURE_STATUS, 0, UserHandle.USER_CURRENT)
+ isGestureLocked = false
+ }
}
fun takeScreenshot(onComplete: ((Uri?) -> Unit)? = null) {
val handler = Handler(Looper.getMainLooper())
ScreenshotHelper(context).takeScreenshot(
- WindowManager.TAKE_SCREENSHOT_FULLSCREEN, true, true,
+ WindowManager.TAKE_SCREENSHOT_FULLSCREEN,
WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS, handler
) { handler.post { onComplete?.invoke(it) } }
}
@@ -99,4 +108,14 @@ class ScreenUtils @Inject constructor(private val context: Context) {
wakelock?.takeIf { it.isHeld }?.release()
}
}
+
+ var lockGesture = false
+ get() = isGestureLocked
+ set(enable) {
+ Settings.System.putIntForUser(context.contentResolver,
+ Settings.System.LOCK_GESTURE_STATUS, if (enable) 1 else 0,
+ UserHandle.USER_CURRENT)
+ field = enable
+ isGestureLocked = enable
+ }
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/BatteryView.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/BatteryView.kt
new file mode 100644
index 00000000..9db7dea9
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/BatteryView.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 The exTHmUI Open Source Project
+ * Copyright (C) 2022-2024 crDroid Android Project
+ * 2021 AOSP-Krypton Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.chaldeaprjkt.gamespace.widget
+
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.BatteryManager
+import android.util.AttributeSet
+import android.widget.TextView
+
+import io.chaldeaprjkt.gamespace.R
+
+@SuppressLint("AppCompatCustomView")
+class BatteryView @JvmOverloads constructor(
+ context: Context,
+ attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0,
+ defStyleRes: Int = 0,
+) : TextView(context, attrs, defStyleAttr, defStyleRes) {
+
+ private val batteryChangeReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action == Intent.ACTION_BATTERY_CHANGED) {
+ val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
+ val scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0)
+ val percent = (level.toFloat() / scale * 100).toInt()
+ text = context.getString(R.string.battery_format, percent)
+ }
+ }
+ }
+
+ init {
+ val batteryManager = context.getSystemService(BatteryManager::class.java)!!
+ text = context.getString(
+ R.string.battery_format,
+ batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
+ )
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ context.registerReceiver(
+ batteryChangeReceiver,
+ IntentFilter(Intent.ACTION_BATTERY_CHANGED)
+ )
+ }
+
+ override fun onDetachedFromWindow() {
+ context.unregisterReceiver(batteryChangeReceiver)
+ super.onDetachedFromWindow()
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/MemoryView.java b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/MemoryView.java
new file mode 100644
index 00000000..8e18c8e9
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/MemoryView.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 crDroid Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.chaldeaprjkt.gamespace.widget;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
+
+import java.lang.Runnable;
+
+import io.chaldeaprjkt.gamespace.R;
+
+public class MemoryView extends TextView {
+
+ private ActivityManager mActivityManager;
+
+ private Handler mHandler;
+ private MemInfoWorker mWorker;
+
+ public MemoryView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ mHandler = new Handler(Looper.getMainLooper());
+ mWorker = new MemInfoWorker();
+ }
+
+ /* Hijack this method to detect visibility rather than
+ * onVisibilityChanged() because the the latter one can be
+ * influenced by more factors, leading to unstable behavior. */
+ @Override
+ public void setVisibility(int visibility) {
+ super.setVisibility(visibility);
+
+ if (visibility == VISIBLE)
+ mHandler.post(mWorker);
+ else
+ mHandler.removeCallbacks(mWorker);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ setVisibility(VISIBLE);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ setVisibility(GONE);
+ super.onDetachedFromWindow();
+ }
+
+ private class MemInfoWorker implements Runnable {
+ @Override
+ public void run() {
+ ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
+ mActivityManager.getMemoryInfo(memInfo);
+ int availMemMiB = (int)(memInfo.availMem / 1048576L);
+ int totalMemMiB = (int)(memInfo.totalMem / 1048576L);
+ setText(getContext().getString(R.string.memory_format, availMemMiB, totalMemMiB));
+
+ mHandler.postDelayed(this, 1000);
+ }
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/MenuSwitcher.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/MenuSwitcher.kt
index ad23367f..c2f5b5f5 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/MenuSwitcher.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/MenuSwitcher.kt
@@ -4,9 +4,10 @@ import android.app.ActivityTaskManager
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
-import android.view.SurfaceControlFpsListener
+import android.view.WindowManager
import android.widget.LinearLayout
import android.widget.TextView
+import android.window.TaskFpsCallback
import io.chaldeaprjkt.gamespace.R
import io.chaldeaprjkt.gamespace.utils.di.ServiceViewEntryPoint
import io.chaldeaprjkt.gamespace.utils.dp
@@ -30,7 +31,7 @@ class MenuSwitcher @JvmOverloads constructor(
private val scope = CoroutineScope(Job() + Dispatchers.Main)
private val taskManager by lazy { ActivityTaskManager.getService() }
- private val surfaceListener = object : SurfaceControlFpsListener() {
+ private val taskFpsCallback = object : TaskFpsCallback() {
override fun onFpsReported(fps: Float) {
if (isAttachedToWindow) {
onFrameUpdated(fps)
@@ -38,12 +39,15 @@ class MenuSwitcher @JvmOverloads constructor(
}
}
+ private val wm: WindowManager
+ get() = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
+
private val content: TextView?
get() = findViewById(R.id.menu_content)
var showFps = false
set(value) {
- layoutParams.width = if (value) LayoutParams.WRAP_CONTENT else 36.dp
+ setMenuIcon(null)
field = value
}
@@ -72,20 +76,31 @@ class MenuSwitcher @JvmOverloads constructor(
private fun updateFrameRateBinding() {
if (showFps) {
- taskManager?.focusedRootTaskInfo?.taskId?.let { surfaceListener.register(it) }
+ taskManager?.focusedRootTaskInfo?.taskId?.let {
+ wm.registerTaskFpsCallback(it, Runnable::run, taskFpsCallback)
+ }
} else {
- surfaceListener.unregister()
+ wm.unregisterTaskFpsCallback(taskFpsCallback)
}
}
- private fun setMenuIcon(icon: Int = R.drawable.ic_close) {
- val ic = if (showFps) null else resources.getDrawable(icon, context.theme)
+ private fun setMenuIcon(icon: Int?) {
+ when (icon) {
+ R.drawable.ic_close, R.drawable.ic_drag -> layoutParams.width = 36.dp
+ else -> layoutParams.width = LayoutParams.WRAP_CONTENT
+ }
+ val ic = icon?.takeIf { !showFps }?.let { resources.getDrawable(it, context.theme) }
content?.textScaleX = if (showFps) 1f else 0f
content?.setCompoundDrawablesRelativeWithIntrinsicBounds(null, ic, null, null)
}
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ updateFrameRateBinding()
+ }
+
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
- surfaceListener.unregister()
+ wm.unregisterTaskFpsCallback(taskFpsCallback)
}
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/PanelView.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/PanelView.kt
index 5771cf96..8032840b 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/PanelView.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/PanelView.kt
@@ -20,14 +20,10 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.WindowInsets
-import android.view.WindowManager
import android.widget.LinearLayout
import androidx.core.view.doOnLayout
import io.chaldeaprjkt.gamespace.R
import io.chaldeaprjkt.gamespace.utils.dp
-import io.chaldeaprjkt.gamespace.utils.isPortrait
-import kotlin.math.max
-import kotlin.math.min
class PanelView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
@@ -48,24 +44,18 @@ class PanelView @JvmOverloads constructor(
}
private fun applyRelativeLocation() {
- val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
- layoutParams.height =
- if (wm.isPortrait()) wm.maximumWindowMetrics.bounds.height() / 2 else LayoutParams.MATCH_PARENT
-
doOnLayout {
if (defaultY == null)
defaultY = y
- y = if (wm.isPortrait()) {
- val safeArea = rootWindowInsets.getInsets(WindowInsets.Type.systemBars())
- val minY = safeArea.top + 16.dp
- val maxY = safeArea.top + (parent as View).height - safeArea.bottom - height - 16.dp
- min(max(relativeY, minY), maxY).toFloat()
+ val safeArea = rootWindowInsets.getInsets(WindowInsets.Type.systemBars())
+ val minY = safeArea.top + 16.dp
+ val maxY = safeArea.top + (parent as View).height - safeArea.bottom - height - 16.dp
+ if (minY > maxY) {
+ y = relativeY.coerceIn(maxY, minY).toFloat()
} else {
- defaultY ?: 16f
+ y = relativeY.coerceIn(minY, maxY).toFloat()
}
-
}
}
-
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/QuickStartAppView.java b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/QuickStartAppView.java
new file mode 100644
index 00000000..2bb644b4
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/QuickStartAppView.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2023-2024 the risingOS Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.chaldeaprjkt.gamespace.widget;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.WindowConfiguration;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.database.ContentObserver;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.window.SplashScreen;
+
+import androidx.annotation.Nullable;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.recyclerview.widget.DefaultItemAnimator;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import io.chaldeaprjkt.gamespace.R;
+
+public class QuickStartAppView extends LinearLayout {
+ private RecyclerView recyclerView;
+ private Context mContext;
+ private SettingsContentObserver mObserver;
+ private PackageManager mPackageManager;
+ private ActivityOptions mActivityOptions;
+
+ public QuickStartAppView(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public QuickStartAppView(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ public QuickStartAppView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ recyclerView = findViewById(R.id.quick_start_app_list);
+ updateAppIcons();
+ }
+
+ private void init(Context context) {
+ mContext = context;
+ mObserver = new SettingsContentObserver(new Handler());
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.getUriFor("quick_start_apps"), true, mObserver);
+ mPackageManager = mContext.getPackageManager();
+ }
+
+ private void updateAppIcons() {
+ String appPackageNames = Settings.System.getString(mContext.getContentResolver(), "quick_start_apps");
+ if (appPackageNames != null && !appPackageNames.isEmpty()) {
+ String[] packages = appPackageNames.split(",");
+ if (packages.length > 0) {
+ setupAppIcons(packages);
+ setVisibility(View.VISIBLE);
+ } else {
+ setVisibility(View.GONE);
+ }
+ } else {
+ setVisibility(View.GONE);
+ }
+ }
+
+ private void setupAppIcons(String[] packages) {
+ recyclerView.setHasFixedSize(true);//设置固定大小
+ recyclerView.setItemAnimator(new DefaultItemAnimator());//设置默认动画
+ LinearLayoutManager mLayoutManage = new LinearLayoutManager(mContext);
+ mLayoutManage.setOrientation(RecyclerView.HORIZONTAL);//设置滚动方向,横向滚动
+ recyclerView.setLayoutManager(mLayoutManage);
+ recyclerView.setAdapter(new MyRecyclerViewAdapter(recyclerView, Arrays.asList(packages)));
+
+ recyclerView.setNestedScrollingEnabled(false);
+ recyclerView.setClipToPadding(false);
+ ViewCompat.setOnApplyWindowInsetsListener(recyclerView, (v, insets) -> {
+ Insets bars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
+ v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(),
+ Math.max(v.getPaddingBottom(), bars.bottom));
+ return insets;
+ });
+ }
+
+ private void setupAppIcon(ImageView imageView, @Nullable String packageName) {
+ if (imageView == null) return;
+ if (packageName == null || packageName.isEmpty()) {
+ imageView.setVisibility(GONE);
+ } else {
+ try {
+ ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
+ imageView.setImageDrawable(mContext.getPackageManager().getApplicationIcon(appInfo));
+ imageView.setOnClickListener(v -> launchAppInFreeformMode(packageName));
+ imageView.setVisibility(VISIBLE);
+ } catch (PackageManager.NameNotFoundException e) {
+ imageView.setVisibility(GONE);
+ }
+ }
+ }
+
+ private void launchAppInFreeformMode(String packageName) {
+ try {
+ PackageManager packageManager = mContext.getPackageManager();
+ Intent launchIntent = packageManager.getLaunchIntentForPackage(packageName);
+ if (launchIntent != null) {
+ String activityName = launchIntent.getComponent().getClassName();
+ Intent freeformIntent = new Intent("com.libremobileos.freeform.START_FREEFORM")
+ .setPackage("com.libremobileos.freeform")
+ .putExtra("packageName", packageName)
+ .putExtra("activityName", activityName)
+ .putExtra("userId", UserHandle.myUserId());
+ mContext.sendBroadcast(freeformIntent);
+ }
+ } catch (Exception e) {}
+ }
+
+ private class SettingsContentObserver extends ContentObserver {
+ SettingsContentObserver(Handler handler) {
+ super(handler);
+ }
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ updateAppIcons();
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mContext.getContentResolver().unregisterContentObserver(mObserver);
+ }
+
+ public class MyRecyclerViewAdapter extends RecyclerView.Adapter {
+ private Context mContext;
+ private List dataList = new ArrayList<>();
+
+ public MyRecyclerViewAdapter(RecyclerView recyclerView) {
+ this.mContext = recyclerView.getContext();
+ }
+
+ public MyRecyclerViewAdapter(RecyclerView recyclerView, List dataList) {
+ this.mContext = recyclerView.getContext();
+ setData(dataList);
+ }
+
+ public void setData(List dataList) {
+ if (null != dataList) {
+ this.dataList.clear();
+ this.dataList.addAll(dataList);
+ notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public RecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(mContext).inflate(R.layout.quick_start_app_item, parent, false);
+ return new RecyclerHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(RecyclerHolder holder, int position) {
+ setupAppIcon(holder.imageView, dataList.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return dataList.size();
+ }
+
+ class RecyclerHolder extends RecyclerView.ViewHolder {
+ ImageView imageView;
+
+ private RecyclerHolder(View itemView) {
+ super(itemView);
+ imageView = itemView.findViewById(R.id.app_icon);
+ imageView.setVisibility(GONE);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/HeadsupTile.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/LockGestureTile.kt
similarity index 65%
rename from app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/HeadsupTile.kt
rename to app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/LockGestureTile.kt
index c62781e0..e2ca2b77 100644
--- a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/HeadsupTile.kt
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/LockGestureTile.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022 crDroid Android Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,19 +19,23 @@ import android.content.Context
import android.util.AttributeSet
import android.view.View
import io.chaldeaprjkt.gamespace.R
+import io.chaldeaprjkt.gamespace.utils.di.ServiceViewEntryPoint
+import io.chaldeaprjkt.gamespace.utils.entryPointOf
-class HeadsupTile @JvmOverloads constructor(
+class LockGestureTile @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : BaseTile(context, attrs) {
+ private val screenUtils by lazy { context.entryPointOf().screenUtils() }
+
override fun onAttachedToWindow() {
super.onAttachedToWindow()
- headsUpEnabled = systemSettings.headsUp
- title?.text = context.getString(R.string.heads_up_title)
- icon?.setImageResource(R.drawable.ic_action_heads_up)
+ shouldLockGesture = appSettings.lockGesture
+ title?.text = context.getString(R.string.lock_gesture_title)
+ icon?.setImageResource(R.drawable.ic_gesture)
}
- private var headsUpEnabled = false
+ private var shouldLockGesture: Boolean = false
set(value) {
field = value
if (value) {
@@ -39,12 +43,13 @@ class HeadsupTile @JvmOverloads constructor(
} else {
summary?.text = context.getString(R.string.state_disabled)
}
- systemSettings.headsUp = value
+ appSettings.lockGesture = value
isSelected = value
+ screenUtils.lockGesture = value
}
override fun onClick(v: View?) {
super.onClick(v)
- headsUpEnabled = !headsUpEnabled
+ shouldLockGesture = !shouldLockGesture
}
}
diff --git a/app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/NotificationTile.kt b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/NotificationTile.kt
new file mode 100644
index 00000000..61d9e3da
--- /dev/null
+++ b/app/src/main/java/io/chaldeaprjkt/gamespace/widget/tiles/NotificationTile.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 Chaldeaprjkt
+ * Copyright (C) 2022 Nameless-AOSP
+ * Copyright (C) 2023 the risingOS Android Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.chaldeaprjkt.gamespace.widget.tiles
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import io.chaldeaprjkt.gamespace.R
+
+class NotificationTile @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null
+) : BaseTile(context, attrs) {
+
+ private var activeMode = true
+ set(value) {
+ field = value
+ appSettings.danmakuNotification = value
+ summary?.text = if (value) {
+ systemSettings.headsup = false
+ context.getString(R.string.notification_danmaku)
+ } else {
+ systemSettings.headsup = true
+ context.getString(R.string.state_default)
+ }
+ isSelected = value
+ }
+
+ override fun onAttachedToWindow() {
+ super.onAttachedToWindow()
+ title?.text = context.getString(R.string.notification_mode_title)
+ activeMode = appSettings.danmakuNotification
+ icon?.setImageResource(R.drawable.ic_action_heads_up)
+ }
+
+ override fun onClick(v: View?) {
+ super.onClick(v)
+ activeMode = !activeMode
+ }
+}
diff --git a/app/src/main/privapp_whitelist_io.chaldeaprjkt.gamespace.xml b/app/src/main/privapp_whitelist_io.chaldeaprjkt.gamespace.xml
index 8a1f1986..77685107 100644
--- a/app/src/main/privapp_whitelist_io.chaldeaprjkt.gamespace.xml
+++ b/app/src/main/privapp_whitelist_io.chaldeaprjkt.gamespace.xml
@@ -16,6 +16,13 @@
-->
+
+
+
+
+
+
+
diff --git a/app/src/main/res/color/tile_ripple_color.xml b/app/src/main/res/color/tile_ripple_color.xml
new file mode 100644
index 00000000..1f8517a0
--- /dev/null
+++ b/app/src/main/res/color/tile_ripple_color.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/bar_dragged.xml b/app/src/main/res/drawable/bar_dragged.xml
deleted file mode 100644
index 99c194f2..00000000
--- a/app/src/main/res/drawable/bar_dragged.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/drawable/bar_expanded.xml b/app/src/main/res/drawable/bar_normal.xml
similarity index 100%
rename from app/src/main/res/drawable/bar_expanded.xml
rename to app/src/main/res/drawable/bar_normal.xml
diff --git a/app/src/main/res/drawable/ic_action_heads_up.xml b/app/src/main/res/drawable/ic_action_heads_up.xml
index 5749b961..a058e928 100644
--- a/app/src/main/res/drawable/ic_action_heads_up.xml
+++ b/app/src/main/res/drawable/ic_action_heads_up.xml
@@ -29,4 +29,4 @@
android:fillColor="@android:color/white"
android:pathData="M 4 3 C 3.47 3 2.961 3.211 2.586 3.586 C 2.211 3.961 2 4.47 2 5 C 2 5.53 2.211 6.039 2.586 6.414 C 2.961 6.789 3.47 7 4 7 C 4.53 7 5.039 6.789 5.414 6.414 C 5.789 6.039 6 5.53 6 5 C 6 4.47 5.789 3.961 5.414 3.586 C 5.039 3.211 4.53 3 4 3 Z"
android:strokeWidth="1" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/drawable/ic_action_record.xml b/app/src/main/res/drawable/ic_action_record.xml
index a47d26dd..b844505f 100644
--- a/app/src/main/res/drawable/ic_action_record.xml
+++ b/app/src/main/res/drawable/ic_action_record.xml
@@ -16,10 +16,9 @@ Copyright (C) 2020 The Android Open Source Project
diff --git a/app/src/main/res/drawable/ic_action_screenshot.xml b/app/src/main/res/drawable/ic_action_screenshot.xml
index 8670761c..5682e90a 100644
--- a/app/src/main/res/drawable/ic_action_screenshot.xml
+++ b/app/src/main/res/drawable/ic_action_screenshot.xml
@@ -19,16 +19,16 @@ Copyright (C) 2018 The Android Open Source Project
android:viewportWidth="20"
android:viewportHeight="20">
diff --git a/app/src/main/res/drawable/ic_arrow_left.xml b/app/src/main/res/drawable/ic_arrow_left.xml
index 5d42237e..5410efa9 100644
--- a/app/src/main/res/drawable/ic_arrow_left.xml
+++ b/app/src/main/res/drawable/ic_arrow_left.xml
@@ -18,8 +18,9 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
- android:viewportHeight="24">
+ android:viewportHeight="24"
+ android:tint="@color/barButtonAccent">
diff --git a/app/src/main/res/drawable/ic_arrow_right.xml b/app/src/main/res/drawable/ic_arrow_right.xml
index b2be38d4..d834980b 100644
--- a/app/src/main/res/drawable/ic_arrow_right.xml
+++ b/app/src/main/res/drawable/ic_arrow_right.xml
@@ -18,8 +18,9 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
- android:viewportHeight="24">
+ android:viewportHeight="24"
+ android:tint="@color/barButtonAccent">
diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml
index 2adb4b4b..d5ede52a 100644
--- a/app/src/main/res/drawable/ic_close.xml
+++ b/app/src/main/res/drawable/ic_close.xml
@@ -18,8 +18,9 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
- android:viewportHeight="24">
+ android:viewportHeight="24"
+ android:tint="@color/barButtonAccent">
diff --git a/app/src/main/res/drawable/ic_custom_seekbar_minus.xml b/app/src/main/res/drawable/ic_custom_seekbar_minus.xml
new file mode 100644
index 00000000..3e45679f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_custom_seekbar_minus.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_custom_seekbar_plus.xml b/app/src/main/res/drawable/ic_custom_seekbar_plus.xml
new file mode 100644
index 00000000..c3bcd98f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_custom_seekbar_plus.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_custom_seekbar_reset.xml b/app/src/main/res/drawable/ic_custom_seekbar_reset.xml
new file mode 100644
index 00000000..409fa129
--- /dev/null
+++ b/app/src/main/res/drawable/ic_custom_seekbar_reset.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_drag.xml b/app/src/main/res/drawable/ic_drag.xml
index e38e5e6b..18c6482b 100644
--- a/app/src/main/res/drawable/ic_drag.xml
+++ b/app/src/main/res/drawable/ic_drag.xml
@@ -18,8 +18,9 @@
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
- android:viewportHeight="24">
+ android:viewportHeight="24"
+ android:tint="@color/barButtonAccent">
diff --git a/app/src/main/res/drawable/ic_gear.xml b/app/src/main/res/drawable/ic_gear.xml
index 8fae13f4..f0590c25 100644
--- a/app/src/main/res/drawable/ic_gear.xml
+++ b/app/src/main/res/drawable/ic_gear.xml
@@ -14,16 +14,17 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0"
+ android:tint="?android:attr/colorControlNormal">
+
diff --git a/app/src/main/res/drawable/ic_gesture.xml b/app/src/main/res/drawable/ic_gesture.xml
new file mode 100644
index 00000000..b65cfc22
--- /dev/null
+++ b/app/src/main/res/drawable/ic_gesture.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_panel.xml b/app/src/main/res/drawable/ic_panel.xml
deleted file mode 100644
index 192ff7b5..00000000
--- a/app/src/main/res/drawable/ic_panel.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
diff --git a/app/src/main/res/drawable/tile_background.xml b/app/src/main/res/drawable/tile_background.xml
index 75c7482e..2e28f09b 100644
--- a/app/src/main/res/drawable/tile_background.xml
+++ b/app/src/main/res/drawable/tile_background.xml
@@ -15,10 +15,10 @@
-->
+ android:color="@color/tile_ripple_color">
-
-
+
diff --git a/app/src/main/res/layout-land/tiles.xml b/app/src/main/res/layout-land/tiles.xml
new file mode 100644
index 00000000..b587d8aa
--- /dev/null
+++ b/app/src/main/res/layout-land/tiles.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/bar_menu_switcher.xml b/app/src/main/res/layout/bar_menu_switcher.xml
index 7bedf997..8c3dcb22 100644
--- a/app/src/main/res/layout/bar_menu_switcher.xml
+++ b/app/src/main/res/layout/bar_menu_switcher.xml
@@ -12,9 +12,10 @@
android:layout_gravity="center"
android:drawableTop="@drawable/ic_arrow_left"
android:minEms="3"
- android:paddingHorizontal="8dp"
+ android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
android:textAlignment="center"
- android:textColor="@color/onBarBackground"
- android:textSize="13sp" />
+ android:textColor="@color/barButtonAccent"
+ android:textSize="14sp"
+ android:textStyle="bold" />
diff --git a/app/src/main/res/layout/library_item.xml b/app/src/main/res/layout/library_item.xml
index 5b50a06b..8d56e788 100644
--- a/app/src/main/res/layout/library_item.xml
+++ b/app/src/main/res/layout/library_item.xml
@@ -58,6 +58,7 @@
android:layout_height="24dp"
android:layout_margin="12dp"
android:scaleType="fitCenter"
- android:src="@drawable/ic_gear" />
+ android:src="@drawable/ic_gear"
+ android:tint="?android:attr/colorControlNormal" />
-
\ No newline at end of file
+
diff --git a/app/src/main/res/layout/panel_view.xml b/app/src/main/res/layout/panel_view.xml
index 20c9a84a..e04374dd 100644
--- a/app/src/main/res/layout/panel_view.xml
+++ b/app/src/main/res/layout/panel_view.xml
@@ -1,25 +1,27 @@
-
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+ app:cardCornerRadius="@*android:dimen/config_dialogCornerRadius">
+ android:padding="13dp">
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ android:layout_marginTop="12dp"
+ android:layout_marginBottom="6dp">
+
+
+
+
+
diff --git a/app/src/main/res/layout/per_app_header.xml b/app/src/main/res/layout/per_app_header.xml
index 3542f163..37ed96a9 100644
--- a/app/src/main/res/layout/per_app_header.xml
+++ b/app/src/main/res/layout/per_app_header.xml
@@ -17,7 +17,7 @@
@@ -25,13 +25,14 @@
android:id="@android:id/icon"
android:layout_width="54dp"
android:layout_height="54dp"
+ android:layout_marginTop="12dp"
android:layout_marginBottom="12dp" />
@@ -39,6 +40,8 @@
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textColor="?android:attr/textColorSecondary" />
+ android:layout_marginBottom="4dp"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="18sp" />
diff --git a/app/src/main/res/layout/quick_start_app_item.xml b/app/src/main/res/layout/quick_start_app_item.xml
new file mode 100644
index 00000000..64e87380
--- /dev/null
+++ b/app/src/main/res/layout/quick_start_app_item.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/tiles.xml b/app/src/main/res/layout/tiles.xml
index 7c6d99e1..f2bc7f38 100644
--- a/app/src/main/res/layout/tiles.xml
+++ b/app/src/main/res/layout/tiles.xml
@@ -1,23 +1,25 @@
-
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
@@ -25,15 +27,19 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
-
-
-
+
+
diff --git a/app/src/main/res/layout/window_panel.xml b/app/src/main/res/layout/window_panel.xml
index 909da32e..81044a85 100644
--- a/app/src/main/res/layout/window_panel.xml
+++ b/app/src/main/res/layout/window_panel.xml
@@ -23,5 +23,5 @@
+ android:layout_height="wrap_content" />
diff --git a/app/src/main/res/layout/window_util.xml b/app/src/main/res/layout/window_util.xml
index cbcd5e2b..5146f6b8 100644
--- a/app/src/main/res/layout/window_util.xml
+++ b/app/src/main/res/layout/window_util.xml
@@ -15,7 +15,6 @@
-->
@@ -26,7 +25,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="10dp"
- android:background="@drawable/bar_expanded"
+ android:background="@drawable/bar_normal"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingVertical="5dp"
@@ -44,7 +43,8 @@
android:layout_marginTop="5dp"
android:padding="8dp"
android:scaleType="centerInside"
- android:src="@drawable/ic_panel" />
+ android:tint="@color/onBarBackground"
+ android:src="@drawable/ic_gear" />
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..4ae7d123
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 00000000..1712766d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp
new file mode 100644
index 00000000..35c41e93
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_background.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
new file mode 100644
index 00000000..015185aa
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..fa62035e
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 00000000..acdf6f1e
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp
new file mode 100644
index 00000000..0fb22932
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_background.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
new file mode 100644
index 00000000..f192edd1
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..ff22161c
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 00000000..4e15eb36
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp
new file mode 100644
index 00000000..ba0bffed
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_background.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
new file mode 100644
index 00000000..ae27e1d6
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..4f2f26fc
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 00000000..4b0d818d
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp
new file mode 100644
index 00000000..ceb79230
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 00000000..16655669
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..dcd10529
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 00000000..d2f78229
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp
new file mode 100644
index 00000000..29a0ef40
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
new file mode 100644
index 00000000..e0e46dfb
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 00000000..c1f5a24b
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/raw-night/game_settings_illustration.json b/app/src/main/res/raw-night/game_settings_illustration.json
deleted file mode 100644
index a5dbc6db..00000000
--- a/app/src/main/res/raw-night/game_settings_illustration.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.7.8","fr":30,"ip":0,"op":240,"w":412,"h":300,"nm":"GameDashboard_anim_v7_dark","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Close btn pulse","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":145,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":155,"s":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[70]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":331,"s":[100]},{"t":343,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[251.845,57.941,0],"ix":2,"l":2},"a":{"a":0,"k":[228.922,131.908,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":155,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":165,"s":[110,110,100]},{"t":175,"s":[200,200,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.717],[5.717,0],[0,-5.716],[-5.717,0]],"o":[[0,-5.716],[-5.717,0],[0,5.717],[5.717,0]],"v":[[10.351,0],[0,-10.351],[-10.351,0],[0,10.351]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.541176470588,0.705882352941,0.972549019608,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[228.922,131.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue300","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue300"}],"ip":145,"op":176,"st":105,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Game btn pulse","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":40,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":50,"s":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[70]},{"t":70,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248.345,149.941,0],"ix":2,"l":2},"a":{"a":0,"k":[228.922,131.908,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":50,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":60,"s":[110,110,100]},{"t":70,"s":[200,200,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.717],[5.717,0],[0,-5.716],[-5.717,0]],"o":[[0,-5.716],[-5.717,0],[0,5.717],[5.717,0]],"v":[[10.351,0],[0,-10.351],[-10.351,0],[0,10.351]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.541176470588,0.705882352941,0.972549019608,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[228.922,131.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue300","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue300"}],"ip":40,"op":71,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Game icn pressed","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":65,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.641,150,0],"ix":2,"l":2},"a":{"a":0,"k":[12,12.25,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.553,0],[0,-0.552],[0.553,0],[0,0.552]],"o":[[0.553,0],[0,0.552],[-0.553,0],[0,-0.552]],"v":[[0,-1],[1,0],[0,1],[-1,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15,9.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".black","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"black"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.553,0],[0,-0.552],[0.553,0],[0,0.553]],"o":[[0.553,0],[0,0.553],[-0.553,0],[0,-0.552]],"v":[[0,-1],[1,0],[0,1],[-1,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[17,12.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".black","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false,"cl":"black"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.5,-2.5],[-0.5,-2.5],[-0.5,-0.5],[-2.5,-0.5],[-2.5,0.5],[-0.5,0.5],[-0.5,2.5],[0.5,2.5],[0.5,0.5],[2.5,0.5],[2.5,-0.5],[0.5,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[8.5,10.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".black","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false,"cl":"black"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.069,-0.09],[0.21,0],[0.1,0.101],[0,0],[0,0],[0,0],[0.15,0],[0.08,0.091],[-0.031,0.21],[0,0],[-0.99,0],[0,0],[-0.139,-0.98],[0,0]],"o":[[-0.08,0.091],[-0.149,0],[0,0],[0,0],[0,0],[-0.1,0.101],[-0.209,0],[-0.081,-0.09],[0,0],[0.149,-0.969],[0,0],[0.989,0],[0,0],[0.03,0.201]],"v":[[7.48,4.81],[7.059,5],[6.669,4.84],[3.831,2],[-3.831,2],[-6.669,4.84],[-7.061,5],[-7.479,4.81],[-7.609,4.371],[-6.52,-3.29],[-4.529,-5],[4.531,-5],[6.51,-3.279],[7.6,4.38]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.219,1.54],[0,0],[1.989,0],[0,0],[0.281,-1.971],[0,0],[-1.549,0],[-0.481,0.481],[0,0],[0,0],[0,0],[-0.67,0]],"o":[[0,0],[-0.281,-1.971],[0,0],[-1.99,0],[0,0],[-0.219,1.54],[0.681,0],[0,0],[0,0],[0,0],[0.48,0.481],[1.561,0]],"v":[[9.581,4.09],[8.49,-3.569],[4.531,-7],[-4.529,-7],[-8.49,-3.569],[-9.581,4.09],[-7.061,7],[-5.26,6.25],[-2.999,4],[3.001,4],[5.251,6.25],[7.049,7]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12,12.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".black","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false,"cl":"black"}],"ip":55,"op":66,"st":55,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Game btn pressed","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":230,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":235,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"t":323,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.641,150.441,0],"ix":2,"l":2},"a":{"a":0,"k":[228.922,131.908,0],"ix":1,"l":2},"s":{"a":0,"k":[140,140,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.717],[5.717,0],[0,-5.716],[-5.717,0]],"o":[[0,-5.716],[-5.717,0],[0,5.717],[5.717,0]],"v":[[10.351,0],[0,-10.351],[-10.351,0],[0,10.351]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[228.922,131.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue400","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue400"}],"ip":55,"op":66,"st":85,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Game icn normal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[0]},{"t":180,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.641,150,0],"ix":2,"l":2},"a":{"a":0,"k":[12,12.25,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.553,0],[0,-0.552],[0.553,0],[0,0.552]],"o":[[0.553,0],[0,0.552],[-0.553,0],[0,-0.552]],"v":[[0,-1],[1,0],[0,1],[-1,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15,9.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue400","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue400"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.553,0],[0,-0.552],[0.553,0],[0,0.553]],"o":[[0.553,0],[0,0.553],[-0.553,0],[0,-0.552]],"v":[[0,-1],[1,0],[0,1],[-1,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[17,12.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue400","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false,"cl":"blue400"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.5,-2.5],[-0.5,-2.5],[-0.5,-0.5],[-2.5,-0.5],[-2.5,0.5],[-0.5,0.5],[-0.5,2.5],[0.5,2.5],[0.5,0.5],[2.5,0.5],[2.5,-0.5],[0.5,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[8.5,10.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue400","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false,"cl":"blue400"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.069,-0.09],[0.21,0],[0.1,0.101],[0,0],[0,0],[0,0],[0.15,0],[0.08,0.091],[-0.031,0.21],[0,0],[-0.99,0],[0,0],[-0.139,-0.98],[0,0]],"o":[[-0.08,0.091],[-0.149,0],[0,0],[0,0],[0,0],[-0.1,0.101],[-0.209,0],[-0.081,-0.09],[0,0],[0.149,-0.969],[0,0],[0.989,0],[0,0],[0.03,0.201]],"v":[[7.48,4.81],[7.059,5],[6.669,4.84],[3.831,2],[-3.831,2],[-6.669,4.84],[-7.061,5],[-7.479,4.81],[-7.609,4.371],[-6.52,-3.29],[-4.529,-5],[4.531,-5],[6.51,-3.279],[7.6,4.38]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.219,1.54],[0,0],[1.989,0],[0,0],[0.281,-1.971],[0,0],[-1.549,0],[-0.481,0.481],[0,0],[0,0],[0,0],[-0.67,0]],"o":[[0,0],[-0.281,-1.971],[0,0],[-1.99,0],[0,0],[-0.219,1.54],[0.681,0],[0,0],[0,0],[0,0],[0.48,0.481],[1.561,0]],"v":[[9.581,4.09],[8.49,-3.569],[4.531,-7],[-4.529,-7],[-8.49,-3.569],[-9.581,4.09],[-7.061,7],[-5.26,6.25],[-2.999,4],[3.001,4],[5.251,6.25],[7.049,7]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12,12.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue400","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false,"cl":"blue400"}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Game btn normal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":180,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":256,"s":[100]},{"t":268,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.641,150.441,0],"ix":2,"l":2},"a":{"a":0,"k":[228.922,131.908,0],"ix":1,"l":2},"s":{"a":0,"k":[140,140,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.717],[5.717,0],[0,-5.716],[-5.717,0]],"o":[[0,-5.716],[-5.717,0],[0,5.717],[5.717,0]],"v":[[10.351,0],[0,-10.351],[-10.351,0],[0,10.351]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[228.922,131.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey900","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey900"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Close btn","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[100]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[251.5,58.375,0],"ix":2,"l":2},"a":{"a":0,"k":[43.75,-88.125,0],"ix":1,"l":2},"s":{"a":0,"k":[60,60,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"f","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[50.75,-93.715],[49.34,-95.125],[43.75,-89.535],[38.16,-95.125],[36.75,-93.715],[42.34,-88.125],[36.75,-82.535],[38.16,-81.125],[43.75,-86.715],[49.34,-81.125],[50.75,-82.535],[45.16,-88.125]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[22.628,21.513],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[43.814,-88.244],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue400","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue400"}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"UI Grid","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[100]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[206,162,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[206,152,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":175,"s":[206,152,0],"to":[0,1.667,0],"ti":[0,-1.667,0]},{"t":180,"s":[206,162,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":7,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[28,34],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey600","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey600"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":7,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30,34],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey600","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false,"cl":"grey600"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":7,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[28,-25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey600","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false,"cl":"grey600"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":7,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30,-25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey600","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false,"cl":"grey600"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"UI Circle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[100]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[206,170,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[206,160,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":175,"s":[206,160,0],"to":[0,1.667,0],"ti":[0,-1.667,0]},{"t":180,"s":[206,170,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[35,-80],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey600","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey600"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[10,-80],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey600","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false,"cl":"grey600"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-15,-80],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey600","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false,"cl":"grey600"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-40,-80],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey600","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false,"cl":"grey600"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"UI Bg","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[100]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-5.514],[0,0],[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0]],"o":[[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0],[0,0],[0,-5.514],[0,0]],"v":[[51.398,-119.204],[61.398,-109.204],[61.398,109.204],[51.398,119.204],[-51.398,119.204],[-61.398,109.204],[-61.398,-109.204],[-51.398,-119.204]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[186.201,142.259],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey800","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey800"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"HW Vol","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[1.271,-12.669],[-1.271,-12.669],[-1.271,12.669],[1.271,12.669]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549019608,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[250.6,106.955],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey700","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey700"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"HW Power","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[1.271,-6.357],[-1.271,-6.357],[-1.271,6.357],[1.271,6.357]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549019608,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[250.6,69.223],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey700","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey700"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"HW Frame","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.627,0],[0,0],[0,-6.627],[0,0],[-6.628,0],[0,0],[0,6.628],[0,0]],"o":[[0,0],[-6.628,0],[0,0],[0,6.628],[0,0],[6.627,0],[0,0],[0,-6.627]],"v":[[51.398,-121.204],[-51.398,-121.204],[-63.398,-109.204],[-63.398,109.204],[-51.398,121.204],[51.398,121.204],[63.398,109.204],[63.398,-109.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,-5.514],[0,0],[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0]],"o":[[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0],[0,0],[0,-5.514],[0,0]],"v":[[51.398,-119.204],[61.398,-109.204],[61.398,109.204],[51.398,119.204],[-51.398,119.204],[-61.398,109.204],[-61.398,-109.204],[-51.398,-119.204]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549019608,0.388235294118,0.407843137255,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[186.201,142.259],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey700","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey700"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Phone Bg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-5.514],[0,0],[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0]],"o":[[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0],[0,0],[0,-5.514],[0,0]],"v":[[51.398,-119.204],[61.398,-109.204],[61.398,109.204],[51.398,119.204],[-51.398,119.204],[-61.398,109.204],[-61.398,-109.204],[-51.398,-119.204]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[186.201,142.259],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Black","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Bg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[412,300],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[187.971,131.945],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bg","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":240,"st":30,"bm":0}],"markers":[{"tm":60,"cm":"OPEN","dr":0},{"tm":210,"cm":"CLOSE","dr":0}]}
\ No newline at end of file
diff --git a/app/src/main/res/raw/game_settings_illustration.json b/app/src/main/res/raw/game_settings_illustration.json
index be46150c..8520db49 100644
--- a/app/src/main/res/raw/game_settings_illustration.json
+++ b/app/src/main/res/raw/game_settings_illustration.json
@@ -1 +1 @@
-{"v":"5.7.8","fr":30,"ip":0,"op":240,"w":412,"h":300,"nm":"GameDashboard_anim_v6_light","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Close btn pulse","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":145,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":155,"s":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":165,"s":[70]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":331,"s":[100]},{"t":343,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[251.845,57.941,0],"ix":2,"l":2},"a":{"a":0,"k":[228.922,131.908,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":155,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":165,"s":[110,110,100]},{"t":175,"s":[200,200,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.717],[5.717,0],[0,-5.716],[-5.717,0]],"o":[[0,-5.716],[-5.717,0],[0,5.717],[5.717,0]],"v":[[10.351,0],[0,-10.351],[-10.351,0],[0,10.351]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.541176470588,0.705882352941,0.972549019608,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[228.922,131.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue300","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue300"}],"ip":145,"op":176,"st":105,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Game btn pulse","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":35,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":45,"s":[50]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[70]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":221,"s":[100]},{"t":233,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[248.095,150.941,0],"ix":2,"l":2},"a":{"a":0,"k":[228.922,131.908,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":45,"s":[200,200,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":55,"s":[110,110,100]},{"t":65,"s":[200,200,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.717],[5.717,0],[0,-5.716],[-5.717,0]],"o":[[0,-5.716],[-5.717,0],[0,5.717],[5.717,0]],"v":[[10.351,0],[0,-10.351],[-10.351,0],[0,10.351]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.541176470588,0.705882352941,0.972549019608,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[228.922,131.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue300","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue300"}],"ip":35,"op":66,"st":-5,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Game icn pressed","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"t":65,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.641,150,0],"ix":2,"l":2},"a":{"a":0,"k":[12,12.25,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.553,0],[0,-0.552],[0.553,0],[0,0.552]],"o":[[0.553,0],[0,0.552],[-0.553,0],[0,-0.552]],"v":[[0,-1],[1,0],[0,1],[-1,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15,9.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".white","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"white"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.553,0],[0,-0.552],[0.553,0],[0,0.553]],"o":[[0.553,0],[0,0.553],[-0.553,0],[0,-0.552]],"v":[[0,-1],[1,0],[0,1],[-1,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[17,12.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".white","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false,"cl":"white"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.5,-2.5],[-0.5,-2.5],[-0.5,-0.5],[-2.5,-0.5],[-2.5,0.5],[-0.5,0.5],[-0.5,2.5],[0.5,2.5],[0.5,0.5],[2.5,0.5],[2.5,-0.5],[0.5,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[8.5,10.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".white","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false,"cl":"white"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.069,-0.09],[0.21,0],[0.1,0.101],[0,0],[0,0],[0,0],[0.15,0],[0.08,0.091],[-0.031,0.21],[0,0],[-0.99,0],[0,0],[-0.139,-0.98],[0,0]],"o":[[-0.08,0.091],[-0.149,0],[0,0],[0,0],[0,0],[-0.1,0.101],[-0.209,0],[-0.081,-0.09],[0,0],[0.149,-0.969],[0,0],[0.989,0],[0,0],[0.03,0.201]],"v":[[7.48,4.81],[7.059,5],[6.669,4.84],[3.831,2],[-3.831,2],[-6.669,4.84],[-7.061,5],[-7.479,4.81],[-7.609,4.371],[-6.52,-3.29],[-4.529,-5],[4.531,-5],[6.51,-3.279],[7.6,4.38]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.219,1.54],[0,0],[1.989,0],[0,0],[0.281,-1.971],[0,0],[-1.549,0],[-0.481,0.481],[0,0],[0,0],[0,0],[-0.67,0]],"o":[[0,0],[-0.281,-1.971],[0,0],[-1.99,0],[0,0],[-0.219,1.54],[0.681,0],[0,0],[0,0],[0,0],[0.48,0.481],[1.561,0]],"v":[[9.581,4.09],[8.49,-3.569],[4.531,-7],[-4.529,-7],[-8.49,-3.569],[-9.581,4.09],[-7.061,7],[-5.26,6.25],[-2.999,4],[3.001,4],[5.251,6.25],[7.049,7]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12,12.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".white","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false,"cl":"white"}],"ip":55,"op":66,"st":55,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Game btn pressed","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":230,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":235,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":311,"s":[100]},{"t":323,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.641,150.441,0],"ix":2,"l":2},"a":{"a":0,"k":[228.922,131.908,0],"ix":1,"l":2},"s":{"a":0,"k":[140,140,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.717],[5.717,0],[0,-5.716],[-5.717,0]],"o":[[0,-5.716],[-5.717,0],[0,5.717],[5.717,0]],"v":[[10.351,0],[0,-10.351],[-10.351,0],[0,10.351]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960784314,0.443137254902,0.898039215686,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[228.922,131.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue600","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue600"}],"ip":55,"op":66,"st":85,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Game icn normal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[0]},{"t":180,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.641,150,0],"ix":2,"l":2},"a":{"a":0,"k":[12,12.25,0],"ix":1,"l":2},"s":{"a":0,"k":[90,90,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.553,0],[0,-0.552],[0.553,0],[0,0.552]],"o":[[0.553,0],[0,0.552],[-0.553,0],[0,-0.552]],"v":[[0,-1],[1,0],[0,1],[-1,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960784314,0.450980392157,0.909803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[15,9.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue600","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue600"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.553,0],[0,-0.552],[0.553,0],[0,0.553]],"o":[[0.553,0],[0,0.553],[-0.553,0],[0,-0.552]],"v":[[0,-1],[1,0],[0,1],[-1,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960784314,0.450980392157,0.909803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[17,12.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue600","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false,"cl":"blue600"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.5,-2.5],[-0.5,-2.5],[-0.5,-0.5],[-2.5,-0.5],[-2.5,0.5],[-0.5,0.5],[-0.5,2.5],[0.5,2.5],[0.5,0.5],[2.5,0.5],[2.5,-0.5],[0.5,-0.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960784314,0.450980392157,0.909803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[8.5,10.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue600","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false,"cl":"blue600"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.069,-0.09],[0.21,0],[0.1,0.101],[0,0],[0,0],[0,0],[0.15,0],[0.08,0.091],[-0.031,0.21],[0,0],[-0.99,0],[0,0],[-0.139,-0.98],[0,0]],"o":[[-0.08,0.091],[-0.149,0],[0,0],[0,0],[0,0],[-0.1,0.101],[-0.209,0],[-0.081,-0.09],[0,0],[0.149,-0.969],[0,0],[0.989,0],[0,0],[0.03,0.201]],"v":[[7.48,4.81],[7.059,5],[6.669,4.84],[3.831,2],[-3.831,2],[-6.669,4.84],[-7.061,5],[-7.479,4.81],[-7.609,4.371],[-6.52,-3.29],[-4.529,-5],[4.531,-5],[6.51,-3.279],[7.6,4.38]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0.219,1.54],[0,0],[1.989,0],[0,0],[0.281,-1.971],[0,0],[-1.549,0],[-0.481,0.481],[0,0],[0,0],[0,0],[-0.67,0]],"o":[[0,0],[-0.281,-1.971],[0,0],[-1.99,0],[0,0],[-0.219,1.54],[0.681,0],[0,0],[0,0],[0,0],[0.48,0.481],[1.561,0]],"v":[[9.581,4.09],[8.49,-3.569],[4.531,-7],[-4.529,-7],[-8.49,-3.569],[-9.581,4.09],[-7.061,7],[-5.26,6.25],[-2.999,4],[3.001,4],[5.251,6.25],[7.049,7]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960784314,0.450980392157,0.909803921569,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12,12.25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue600","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false,"cl":"blue600"}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Game btn normal","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":180,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":256,"s":[100]},{"t":268,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.641,150.441,0],"ix":2,"l":2},"a":{"a":0,"k":[228.922,131.908,0],"ix":1,"l":2},"s":{"a":0,"k":[140,140,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,5.717],[5.717,0],[0,-5.716],[-5.717,0]],"o":[[0,-5.716],[-5.717,0],[0,5.717],[5.717,0]],"v":[[10.351,0],[0,-10.351],[-10.351,0],[0,10.351]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.941176470588,0.996078431373,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[228.922,131.908],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue50","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue50"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Close btn","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[100]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[251.5,58.375,0],"ix":2,"l":2},"a":{"a":0,"k":[43.75,-88.125,0],"ix":1,"l":2},"s":{"a":0,"k":[60,60,100],"ix":6,"l":2}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"f","pt":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[50.75,-93.715],[49.34,-95.125],[43.75,-89.535],[38.16,-95.125],[36.75,-93.715],[42.34,-88.125],[36.75,-82.535],[38.16,-81.125],[43.75,-86.715],[49.34,-81.125],[50.75,-82.535],[45.16,-88.125]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[22.628,21.513],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.101960784314,0.447058823529,0.901960784314,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[43.814,-88.244],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".blue600","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"blue600"}],"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"UI Grid","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[100]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[206,162,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[206,152,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":175,"s":[206,152,0],"to":[0,1.667,0],"ti":[0,-1.667,0]},{"t":180,"s":[206,162,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":7,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[28,34],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey300","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey300"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":7,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30,34],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey300","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false,"cl":"grey300"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":7,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[28,-25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey300","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false,"cl":"grey300"},{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[50,50],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":7,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-30,-25],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey300","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false,"cl":"grey300"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"UI Circle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[100]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[206,170,0],"to":[0,-1.667,0],"ti":[0,1.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[206,160,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":175,"s":[206,160,0],"to":[0,1.667,0],"ti":[0,-1.667,0]},{"t":180,"s":[206,170,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[35,-80],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey300","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey300"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[10,-80],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey300","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false,"cl":"grey300"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-15,-80],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey300","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false,"cl":"grey300"},{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[20,20],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.854901960784,0.862745098039,0.878431372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-40,-80],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey300","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false,"cl":"grey300"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"UI Bg","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":60,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":65,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":175,"s":[100]},{"t":180,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-5.514],[0,0],[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0]],"o":[[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0],[0,0],[0,-5.514],[0,0]],"v":[[51.398,-119.204],[61.398,-109.204],[61.398,109.204],[51.398,119.204],[-51.398,119.204],[-61.398,109.204],[-61.398,-109.204],[-51.398,-119.204]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.909803921569,0.917647058824,0.929411764706,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[186.201,142.259],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey200","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey200"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"HW Vol","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[1.271,-12.669],[-1.271,-12.669],[-1.271,12.669],[1.271,12.669]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[250.6,106.955],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey400","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey400"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"HW Power","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[1.271,-6.357],[-1.271,-6.357],[-1.271,6.357],[1.271,6.357]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[250.6,69.223],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey400","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey400"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"HW Frame","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.627,0],[0,0],[0,-6.627],[0,0],[-6.628,0],[0,0],[0,6.628],[0,0]],"o":[[0,0],[-6.628,0],[0,0],[0,6.628],[0,0],[6.627,0],[0,0],[0,-6.627]],"v":[[51.398,-121.204],[-51.398,-121.204],[-63.398,-109.204],[-63.398,109.204],[-51.398,121.204],[51.398,121.204],[63.398,109.204],[63.398,-109.204]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,-5.514],[0,0],[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0]],"o":[[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0],[0,0],[0,-5.514],[0,0]],"v":[[51.398,-119.204],[61.398,-109.204],[61.398,109.204],[51.398,119.204],[-51.398,119.204],[-61.398,109.204],[-61.398,-109.204],[-51.398,-119.204]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.741176470588,0.756862745098,0.776470588235,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[186.201,142.259],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".grey400","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"grey400"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Phone bg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-5.514],[0,0],[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0]],"o":[[5.514,0],[0,0],[0,5.513],[0,0],[-5.515,0],[0,0],[0,-5.514],[0,0]],"v":[[51.398,-119.204],[61.398,-109.204],[61.398,109.204],[51.398,119.204],[-51.398,119.204],[-61.398,109.204],[-61.398,-109.204],[-51.398,-119.204]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[186.201,142.259],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".white","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"white"}],"ip":0,"op":240,"st":30,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Bg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,160,0],"ix":2,"l":2},"a":{"a":0,"k":[187.577,141.967,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[412,300],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":28,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[187.971,131.945],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":".white","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"cl":"white"}],"ip":0,"op":240,"st":30,"bm":0}],"markers":[{"tm":60,"cm":"OPEN","dr":0},{"tm":210,"cm":"CLOSE","dr":0}]}
\ No newline at end of file
+{"v":"5.7.7","fr":29,"ip":0,"op":110,"w":200,"h":200,"nm":"toturial_fps01","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"fps 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":8,"s":[100]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":14,"s":[100]},{"t":19,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[46.442,90,0],"ix":2,"l":2},"a":{"a":0,"k":[6.471,6.471,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":6,"s":[43,43,100]},{"t":11,"s":[92,92,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.713725490196,0.521568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.471,6.471],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.713725490196,0.521568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.471,6.471],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[160,160],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":43,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 6","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":145,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"fps","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[100]},{"t":35,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[46.442,90,0],"ix":2,"l":2},"a":{"a":0,"k":[6.471,6.471,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.326,0],[0.26,0.092],[0.161,0.147],[0,0],[-0.21,-0.082],[-0.208,0],[-0.111,0.084],[0,0.139],[0.064,0.068],[0.104,0.041],[0.176,0.049],[0.172,0.078],[0.122,0.172],[0,0.287],[-0.111,0.203],[-0.225,0.119],[-0.323,0],[-0.215,-0.066],[-0.161,-0.123],[0,0],[0.327,0],[0.109,-0.09],[0,-0.147],[-0.125,-0.071],[-0.262,-0.07],[-0.172,-0.078],[-0.123,-0.168],[0,-0.287],[0.113,-0.204],[0.226,-0.119]],"o":[[-0.28,0],[-0.26,-0.093],[0,0],[0.151,0.135],[0.21,0.082],[0.233,0],[0.111,-0.084],[0,-0.103],[-0.065,-0.067],[-0.104,-0.041],[-0.269,-0.078],[-0.172,-0.078],[-0.122,-0.173],[0,-0.251],[0.111,-0.203],[0.224,-0.119],[0.226,0],[0.215,0.065],[0,0],[-0.326,-0.225],[-0.229,0],[-0.109,0.091],[0,0.148],[0.126,0.072],[0.269,0.078],[0.172,0.078],[0.124,0.168],[0,0.246],[-0.112,0.203],[-0.226,0.119]],"v":[[-0.033,2.227],[-0.842,2.09],[-1.473,1.73],[-1.195,0.979],[-0.654,1.305],[-0.027,1.428],[0.49,1.301],[0.656,0.967],[0.56,0.71],[0.307,0.548],[-0.113,0.413],[-0.775,0.178],[-1.215,-0.197],[-1.398,-0.885],[-1.232,-1.566],[-0.729,-2.048],[0.092,-2.227],[0.753,-2.128],[1.318,-1.846],[1.064,-1.089],[0.085,-1.428],[-0.423,-1.292],[-0.587,-0.936],[-0.398,-0.607],[0.182,-0.393],[0.844,-0.16],[1.288,0.21],[1.473,0.893],[1.303,1.566],[0.796,2.049]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.321568627451,0.137254901961,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[9.631,6.607],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.129,0.113],[0,0.208],[0.129,0.112],[0.244,0],[0,0],[0,0]],"o":[[0.244,0],[0.129,-0.113],[0,-0.211],[-0.129,-0.113],[0,0],[0,0],[0,0]],"v":[[-0.153,-0.21],[0.406,-0.379],[0.6,-0.861],[0.406,-1.347],[-0.153,-1.517],[-0.61,-1.517],[-0.61,-0.21]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-0.231,-0.111],[-0.126,-0.204],[0,-0.279],[0.125,-0.207],[0.231,-0.109],[0.312,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0.312,0],[0.231,0.111],[0.125,0.205],[0,0.276],[-0.126,0.206],[-0.231,0.109],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-0.11,-2.227],[0.705,-2.06],[1.24,-1.587],[1.428,-0.861],[1.24,-0.137],[0.705,0.336],[-0.11,0.5],[-0.61,0.5],[-0.61,2.227],[-1.428,2.227],[-1.428,-2.227]],"c":true},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 2","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.321568627451,0.137254901961,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.447,6.606],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":5,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-0.411,-1.528],[-0.411,-0.533],[1.014,-0.533],[1.014,0.167],[-0.411,0.167],[-0.411,2.227],[-1.229,2.227],[-1.229,-2.227],[1.229,-2.227],[1.229,-1.528]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.321568627451,0.137254901961,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[3.111,6.606],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.713725490196,0.521568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.471,6.471],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":145,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"sidebar","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[100]},{"t":35,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[45.882,100.588,0],"ix":2,"l":2},"a":{"a":0,"k":[29.412,40.588,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.647,65.294],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.647,47.647],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.647,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[47.647,12.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30,65.294],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 5","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30,47.647],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[30,12.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.353,65.294],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 8","np":3,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.353,47.647],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 9","np":3,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.353,30],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 10","np":3,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.574,0],[0,-3.574],[3.574,0],[0,3.573]],"o":[[3.574,0],[0,3.573],[-3.574,0],[0,-3.574]],"v":[[0,-6.471],[6.471,0.001],[0,6.471],[-6.471,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.878431432387,0.450980422076,0.094117654539,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.353,12.353],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 11","np":3,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.657,0],[0,0],[0,-1.657],[0,0],[1.656,0],[0,0],[0,1.657],[0,0]],"o":[[0,0],[1.656,0],[0,0],[0,1.657],[0,0],[-1.657,0],[0,0],[0,-1.657]],"v":[[-26.412,-40.588],[26.412,-40.588],[29.412,-37.588],[29.412,37.588],[26.412,40.588],[-26.412,40.588],[-29.412,37.588],[-29.412,-37.588]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.321568627451,0.137254901961,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[29.412,40.588],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 12","np":3,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":145,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"60","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":40,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":55,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":96,"s":[100]},{"t":108,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.316,78.323,0],"ix":2,"l":2},"a":{"a":0,"k":[7.188,5.113,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.301,0.49],[0.652,0],[0.297,-0.487],[0.01,-1.011],[0,0],[-0.313,-0.514],[-0.633,0],[-0.303,0.484],[-0.014,1.039]],"o":[[0,-1.071],[-0.301,-0.489],[-0.646,0],[-0.296,0.488],[0,0],[0,1.075],[0.311,0.511],[0.625,0],[0.303,-0.483],[0,0]],"v":[[1.877,-0.998],[1.426,-3.34],[-0.003,-4.074],[-1.418,-3.343],[-1.876,-1.094],[-1.876,0.93],[-1.407,3.313],[0.011,4.081],[1.402,3.356],[1.877,1.073]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0.506,-0.719],[1.076,0],[0.511,0.705],[0.019,1.4],[0,0],[-0.506,0.711],[-1.08,0],[-0.506,-0.686],[-0.014,-1.431]],"o":[[0,1.482],[-0.506,0.72],[-1.062,0],[-0.509,-0.703],[0,0],[0,-1.463],[0.506,-0.711],[1.071,0],[0.506,0.686],[0,0]],"v":[[3.142,0.731],[2.383,4.033],[0.011,5.113],[-2.348,4.057],[-3.141,0.902],[-3.141,-0.786],[-2.382,-4.047],[-0.003,-5.113],[2.362,-4.084],[3.142,-0.909]],"c":true},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.713725490196,0.521568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[11.236,5.113],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.547,0],[0.364,-0.26],[0.141,-0.391],[0,0],[-0.37,-0.501],[-0.551,0],[-0.325,0.418],[0,0.679],[0.331,0.422]],"o":[[-0.434,0],[-0.366,0.259],[0,0],[0,0.82],[0.369,0.501],[0.57,0],[0.326,-0.419],[0,-0.684],[-0.33,-0.421]],"v":[[0.082,-0.564],[-1.114,-0.174],[-1.873,0.803],[-1.873,1.268],[-1.319,3.25],[0.061,4.002],[1.404,3.374],[1.894,1.726],[1.397,0.068]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0.583,-0.566],[0.091,-1.026],[-0.907,0],[-0.516,-0.61],[0,-0.966],[0.558,-0.615],[0.939,0],[0.592,0.732],[0,1.154],[0,0],[-0.781,0.968],[-1.545,0.022]],"o":[[0,0],[0,0],[-0.985,0.018],[-0.584,0.565],[0.524,-0.602],[0.865,0],[0.518,0.611],[0,1.025],[-0.558,0.616],[-0.953,0],[-0.593,-0.731],[0,0],[0,-1.832],[0.783,-0.969],[0,0]],"v":[[1.743,-5.048],[1.743,-3.975],[1.511,-3.975],[-0.841,-3.1],[-1.853,-0.714],[0.294,-1.617],[2.368,-0.701],[3.145,1.665],[2.307,4.125],[0.061,5.048],[-2.256,3.951],[-3.145,1.124],[-3.145,0.639],[-1.973,-3.561],[1.518,-5.048]],"c":true},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 2","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.713725490196,0.521568627451,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[3.145,5.178],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":5,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":145,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"cycle","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":49,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":96,"s":[100]},{"t":108,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.317,78.323,0],"ix":2,"l":2},"a":{"a":0,"k":[19.074,19.074,0],"ix":1,"l":2},"s":{"a":0,"k":[84,84,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-10.353,0],[0,-10.353],[10.353,0],[0,10.352]],"o":[[10.353,0],[0,10.352],[-10.353,0],[0,-10.353]],"v":[[0,-18.824],[18.824,0.001],[0,18.824],[-18.824,0.001]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":4,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.321568627451,0.137254901961,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[19.074,19.074],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":145,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"bg","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100,100,0],"ix":2,"l":2},"a":{"a":0,"k":[99.729,93.191,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,2.603],[0,0],[-2.603,0],[0,0],[0,-2.603],[0,0],[2.602,0],[0,0]],"o":[[-2.603,0],[0,0],[0,-2.603],[0,0],[2.602,0],[0,0],[0,2.602],[0,0],[0,0]],"v":[[-84.45,44.874],[-89.207,40.117],[-89.207,-40.117],[-84.45,-44.874],[84.451,-44.874],[89.207,-40.117],[89.207,40.028],[84.451,44.784],[-84.45,44.784]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.101960791794,0.090196078431,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[99.551,92.952],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.075,5.481],[0,0],[1.075,5.392],[5.556,0],[0,0],[1.165,-5.481],[0,0],[-1.075,-5.481],[-5.556,0],[0,0]],"o":[[1.075,-5.391],[0,0],[-1.075,-5.481],[0,0],[-5.557,0],[-1.075,4.942],[0,0],[1.075,5.481],[0,0],[5.556,-0.09]],"v":[[97.866,38.593],[99.479,-0.045],[97.866,-38.683],[86.395,-48.118],[-86.484,-48.118],[-97.956,-38.773],[-99.479,0.045],[-97.866,38.683],[-86.395,48.118],[86.395,48.118]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.180392156863,0.192156877705,0.20000001496,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[99.729,93.191],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-51.33,0],[0,-51.33],[51.33,0],[0,51.33]],"o":[[51.33,0],[0,51.33],[-51.33,0],[0,-51.33]],"v":[[0,-92.941],[92.941,0],[0,92.941],[-92.941,0]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.301960784314,0.270588235294,0.258823529412,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[99.729,93.191],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":176,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/app/src/main/res/values-af-rZA/strings.xml b/app/src/main/res/values-af-rZA/strings.xml
new file mode 100644
index 00000000..c19563ca
--- /dev/null
+++ b/app/src/main/res/values-af-rZA/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Quick Start Apps
+ Select apps to launch quickly
+ Game Space
+ Bestuur jou speletjie-opstelling
+
+ In-speletjie opsies
+ Blokkeer volskermgebeurtenisse
+ Verhoed dat volskermgebeurtenisse soos inkomende oproepe verskyn
+ Bly wakker
+ Sluit gebaar
+ Deaktiveer outo-helderheid
+ Disable three fingers swipe gesture
+ Deaktiveer \"USB debugging\"
+ Oorleg kieslys ondeursigtigheid vlak
+
+ Kennisgewingmodus
+ Moet nie wys
+ Wys as \"Heads Up\"
+ Wys as \"reTicker\"
+ Wys as \"Danmaku\"
+
+ Belmodus
+ Stil
+ Vibreer
+ Normaal
+ Moet nie verander
+
+ Biblioteek
+ Voeg by
+ Kies jou speletjie
+ Soek
+ Is jy seker dat jy %1$s van jou speletjieslys wil verwyder?
+
+ Stel speletjie in
+ Voorkeurmodus
+ Gebruik ANGLE (eksperimenteel)
+ Gebruik ANGLE weergawe in plaas van die inheemse GLES bestuurders.\nWAARSKUWING!!! Mag speletjie se grafika verbreek, gebruik versigtig!
+ ANGLE is nie op jou stelsel beskikbaar nie
+ Verwyder %1$s van biblioteek
+ Ongesteun
+ Standaard
+ Werkverrigting
+ Battery
+
+ Waarde %s
+ by verstek
+ Standaard waarde: %s\nLang tik om te stel
+ Standaard waarde is gestel
+
+ Battery: %1$d%%
+ Geheue beskikbaar: %1$d\/%2$d MB
+
+ Modus
+ FPS informasie
+ Steek weg
+ \"Heads Up\"
+ \"reTicker\"
+ \"Danmaku\"
+ Geaktiveer
+ Gedeaktiveer
+ Default
+ Oproepmodus
+ Geen aksie
+ Outo-antwoord
+ Outo-verwerp
+ Oproep vanaf %1$s ontvang
+ Oproep vanaf %1$s verwerp
+
+ Danmaku Notification mode
+ Show notification as danmaku aka bullet comments while game is active
+ Game Space is running
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml
new file mode 100644
index 00000000..eb2c4c33
--- /dev/null
+++ b/app/src/main/res/values-ar-rSA/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ تطبيقات البداية السريعة
+ حدد التطبيقات للتشغيل السريع
+ وضع الألعاب
+ إدارة إعدادات ألعابك
+
+ خيارات داخل اللعبة
+ منع أحداث الشاشة الكاملة
+ منع أحداث ملء الشاشة مثل المكالمات الواردة من الظهور أثناء اللعب
+ البقاء في الوضع النشط
+ قفل الايماءات
+ تعطيل السطوع التلقائي
+ تعطيل السحب بثلاثة أصابع لأخذ لقطة الشاشة
+ تعطيل تصحيح أخطاء USB
+ مستوى شفافية القائمة العائمة
+
+ وضع الإشعارات
+ اخفاء
+ إظهار كتنبيهات
+ إظهار كمؤشر
+ إظهار ك Danmaku
+
+ وضع الرنين
+ صامت
+ إهتزاز
+ عادي
+ لا تقم بالتغيير
+
+ المكتبة
+ إضافة
+ إختر لعبتك
+ بحث
+ هل أنت متحقِّق من أنك تريد إزالة %1$s من قائمة ألعابك؟
+
+ ضبط اللعبة
+ الوضع المفضل
+ استخدام واجهة المستخدم الجديدة (التجريبية)
+ استخدام محرك ANGLE بدلاً من تعاريف GLES التقليدية. \n تحذير!! قد يعطل رسومات اللعبة، استخدم بحذر!
+ ANGLE غير متوفر على النظام الخاص بك
+ إزالة %1$s من المكتبة
+ غير مدعوم
+ قياسي
+ نمط الاداء
+ توفير البطارية
+
+ القيمة: %s
+ بشكل افتراضي
+ القيمة الافتراضية: %s\n أنقر مطولاً للتعيين
+ تم تعيين القيمة الافتراضية
+
+ البطارية: %1$d%%
+ الذاكرة المتاحة: %1$d\/%2$d ميغابايت
+
+ الوضع
+ عداد معدل الإطارات
+ إخفاء
+ التنبيهات العلوية
+ reTicker
+ Danmaku
+ مفعّل
+ معطل
+ افتراضية
+ وضع المكالمة
+ بلا إجراء
+ رد تلقائي
+ رفض تلقائي
+ مكالمة متلقاة منذ %1$s
+ مكالمة مرفوضة منذ%1$s
+
+ وضع إشعار Danmaku
+ إظهار تنبيه Danmaku كما هو معروف باِسم تعليقات سريعة عندما تكون اللعبة نشطة
+
+
+ عرض المكالمة
+ إظهار الحد الأدنى من تراكب المكالمات للإجابة / رفض المكالمات
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml
new file mode 100644
index 00000000..bceee2c4
--- /dev/null
+++ b/app/src/main/res/values-ca-rES/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Quick Start Apps
+ Select apps to launch quickly
+ Espai de Jocs
+ Gestiona la configuració de joc
+
+ Opcions en el joc
+ Bloqueja els esdeveniments a pantalla completa
+ Impedeix els esdeveniments a pantalla completa com trucades entrants
+ Mantén la pantalla encesa
+ Gest de bloqueig
+ Desactiva la brillantor automàtica
+ Disable three fingers swipe gesture
+ Desactiva la depuració USB
+ Nivell d\'opacitat del menú flotant
+
+ Mode de notificació
+ No ho mostris
+ Mostra com a notificació emergent
+ Mostra amb el reTicker
+ Mostra amb el Danmaku
+
+ Mode amb so
+ Silenci
+ Vibració
+ Normal
+ No el canviïs
+
+ Biblioteca
+ Afegeix
+ Trieu el joc
+ Cerca
+ Segur que voleu eliminar %1$s de la llista de jocs?
+
+ Configura el joc
+ Mode preferit
+ Utilitza l\'ANGLE (experimental)
+ Utilitza el renderitzador ANGLE en lloc dels controladors natius GLES.\nATENCIÓ! Pot trenca els gràfics del joc, utilitzeu amb precaució!
+ ANGLE no està disponible en el sistema
+ Elimina %1$s de la biblioteca
+ No suportat
+ Estàndard
+ De rendiment
+ Bateria
+
+ Valor: %s
+ per defecte
+ Valor per defecte: %s\nPremeu prolongadament per a establir-lo
+ El valor per defecte s\'ha establert
+
+ Bateria: %1$d%%
+ Memòria disponible: %1$d\/%2$d MB
+
+ Mode
+ Informació dels FPS
+ Amaga
+ Notificacions emergents
+ reTicker
+ Danmaku
+ Activat
+ Desactivat
+ Per defecte
+ Mode de trucada
+ Sense acció
+ Resposta automàtica
+ Rebutja automàticament
+ S\'ha rebut una trucada de %1$s
+ S\'ha rebutjat una trucada de %1$s
+
+ Mode de Notificació Danmaku
+ Mostra notificació mentre el joc està actiu
+ Game Space is running
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml
new file mode 100644
index 00000000..717743fe
--- /dev/null
+++ b/app/src/main/res/values-cs-rCZ/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Rychlé spuštění aplikací
+ Vyberte aplikace pro rychlé spuštění
+ Herní prostor
+ Spravovat herního nastavení
+
+ Možnosti ve hře
+ Blokovat událost na celou obrazovku
+ Zakázat zobrazení celoobrazovkových události, např. příchozí volání
+ Nevypínat obrazovku
+ Zakázat gesta
+ Zakázat automatický jas
+ Zakázat gesto přejetím třemi prsty
+ Zakázat ladění USB
+ Úroveň průhlednosti překrytí menu
+
+ Režim upozornění
+ Nezobrazovat
+ Zobrazit jako plovoucí oznámení
+ Zobrazit jako reTicker
+ Zobrazit jako Danmaku
+
+ Režim vyzvánění
+ Tichý
+ Vibrace
+ Normální
+ Neměnit
+
+ Knihovna
+ Přidat
+ Výběr hry
+ Hledat
+ Opravdu chcete odstranit %1$s z vaší herní knihovny?
+
+ Konfigurace hry
+ Preferovaný režim
+ Použít ANGLE (experimentální)
+ Používá ANGLE renderer místo nativních ovladačů GLA.\nVAROVÁNÍ!! Může se rozbít herní grafiku, používejte opatrně!
+ ANGLE není k dispozici ve vašem systému
+ Odebrat %1$s z knihovny
+ Nepodporováno
+ Standardní
+ Výkon
+ Baterie
+
+ Hodnota: %s
+ výchozí hodnota
+ Výchozí hodnota: %s\nDlouze klepněte pro její nastavení
+ Výchozí hodnota je nastavena
+
+ Baterie: %1$d%%
+ Dostupná paměť: %1$d\/%2$d MB
+
+ Režim
+ Informace o FPS
+ Skrýt
+ Plovoucí oznámení
+ reTicker
+ Danmaku
+ Povoleno
+ Zakázáno
+ Výchozí
+ Režim volání
+ Žádná akce
+ Automatická odpověď
+ Automaticky odmítnout
+ Odmítnutý hovor od %1$s
+ Zamítnutý hovor z %1$s
+
+ Režim upozornění Danmaku
+ Zobrazit oznámení jako odrážku pro danmaku akci, pokud je hra aktivní
+ Herní prostředí běží
+
+ Překrytí hovoru
+ Zobrazit minimální překrytí hovorů pro odpověď/odmítnutí hovorů
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml
new file mode 100644
index 00000000..b7cc3808
--- /dev/null
+++ b/app/src/main/res/values-da-rDK/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Quick Start Apps
+ Select apps to launch quickly
+ Spil Rum
+ Administrer dit spilopsætning
+
+ Indstillinger for spil
+ Bloker begivenhed i fuldskærm
+ Forhindr fuldskærms-begivenheder som indgående opkald i at blive vist
+ Forbliv vågen
+ Lås gestus
+ Deaktiver auto-lysstyrke
+ Disable three fingers swipe gesture
+ Deaktiver USB-fejlretning
+ Overlay menu opacitet niveau
+
+ Notifikations tilstand
+ Vis ikke
+ Vis som Heads Up
+ Vis som reTicker
+ Vis som Danmaku
+
+ Ringetilstand
+ Stille
+ Vibrere
+ Normal
+ Ikke skift
+
+ Bibliotek
+ Tilføj
+ Vælg dit spil
+ Søg
+ Er du sikker på, at du vil fjerne %1$s fra din spilliste?
+
+ Konfigurer spil
+ Foretrukken tilstand
+ Brug ANGLE (eksperimentel)
+ Brug ANGLE renderer i stedet for indfødte GLES drivere.\nADVARSEL!!! Kan ødelægge spilgrafik, brug med forsigtighed!
+ ANGLE er ikke tilgængelig på dit system
+ Fjern %1$s fra bibliotek
+ Uunderstøttet
+ Standard
+ Ydeevne
+ Batteri
+
+ Værdi: %s
+ som standard
+ Standardværdi: %s\nLangt tryk for at indstille
+ Standard værdi er sat
+
+ Batteri: %1$d%%
+ Tilgængelig hukommelse: %1$d\/%2$d MB
+
+ Tilstand
+ FPS info
+ Skjul
+ Banner Opad
+ reTicker
+ Danmaku
+ Aktiveret
+ Deaktiveret
+ Standard
+ Opkaldstilstand
+ Ingen handling
+ Automatisk svar
+ Automatisk afvisning
+ Modtaget opkald fra %1$s
+ Afviste opkald fra %1$s
+
+ Danmaku-meddelelsestilstand
+ Show notification as danmaku aka bullet comments while game is active
+ Game Space is running
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml
new file mode 100644
index 00000000..a4818bde
--- /dev/null
+++ b/app/src/main/res/values-de-rDE/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Schnellstart-Apps
+ Apps für Schnellstart auswählen
+ Spielmodus
+ Spieleinrichtung verwalten
+
+ In-Game-Optionen
+ Vollbild-Ereignis blockieren
+ Deaktivieren von Vollbildbenachrichtigungen (z. B. eingehende Anrufe)
+ Display eingeschaltet lassen
+ Gesten deaktivieren
+ Auto-Helligkeit deaktivieren
+ Geste „Streichen mit drei Fingern“ deaktivieren
+ USB-Debugging deaktivieren
+ Transparenz des Overlay-Menüs
+
+ Benachrichtigungsmodus
+ Nicht anzeigen
+ Als Pop-up anzeigen
+ Als reTicker anzeigen
+ Als Danmaku anzeigen
+
+ Klingelmodus
+ Stumm
+ Vibration
+ Normal
+ Nicht ändern
+
+ Bibliothek
+ Hinzufügen
+ Wähle dein Spiel
+ Suchen
+ Soll %1$s wirklich aus der Spielebibliothek entfernt werden?
+
+ Spiel konfigurieren
+ Bevorzugter Modus
+ ANGLE benutzen (experimentell)
+ Verwendung von ANGLE Renderer statt nativer GLES Treiber.\nWARNUNG!! Kann Spielgrafiken falsch darstellen!
+ ANGLE ist auf Ihrem System nicht verfügbar
+ %1$s aus der Bibliothek entfernen
+ Nicht unterstützt
+ Standard
+ Leistung
+ Akku
+
+ Wert: %s
+ Standardmäßig
+ Standardwert: %s\nZum Einstellen gedrückt halten
+ Standardwert ist eingestellt
+
+ Akku: %1$d%%
+ Freier Arbeitsspeicher: %1$d\/%2$d MB
+
+ Modus
+ FPS-Info
+ Ausblenden
+ Pop-up
+ reTicker
+ Danmaku
+ Aktiviert
+ Deaktiviert
+ Standard
+ Anruf-Modus
+ Keine Aktion
+ Automatisch ans Telefon gehen
+ Automatisch ablehnen
+ Empfangener Anruf von %1$s
+ Abgelehnter Anruf von %1$s
+
+ Benachrichtigungsmodus „Danmaku“
+ Bei aktivem Spiel Benachrichtigungen als „Bullet-Kommentare“ aka „Danmaku“ anzeigen
+ Spielmodus läuft
+
+ Zeige Overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
deleted file mode 100644
index 16431383..00000000
--- a/app/src/main/res/values-de/strings.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
- Game Space
- Verwalten Sie Ihre Spieleinstellungen
- Wählen Sie ein Spiel
- Auto-Helligkeit deaktivieren
- Die Helligkeit im Spiel beibehalten
- Heads-up deaktivieren
- Deaktivieren der Benachrichtigungsvorschau im Spiel
- Bibliothek
- Bist Du sicher, dass du %1$s aus Deiner Bibliothek entfernen möchtest ?
- Suche
- Vorübergehende Deaktivierung der Screenshotgeste mit drei Fingern im Spiel
- Wischen für Bildschirmfoto deaktivieren
- chaldeaprjkt
- aktiviert
- daktiviert
-
- Modus
-
- - Nicht unterstützt
- - Standard
- - Performance
- - Akkuschonend
-
- Heads-up
- FPS-Info
- Bildschirm wach halten
- Bildschirm während des Spiels wach halten
-
- Klingelmodus im Spiel
-
- - Still
- - Vibration
- - Normal
-
-
- Vollbild-Ereignisse blockieren
- Verhindern, dass Vollbild-Ereignisse wie eingehende Anrufe im Spiel angezeigt werden
-
- Spiel konfigurieren
- Bevorzugter Modus
-
- - Standard
- - Performance
- - Akkuschonend
-
-
- ANGLE verwenden (experimentell)
- Verwenden des ANGLE-Renderers anstelle der nativen GLES-Treiber.\nWARNUNG!! Kann Spielgrafiken beschädigen, mit Vorsicht verwenden!
- ANGLE ist auf Deinem System nicht verfügbar
-
- %1$s aus der Bibliothek entfernen
-
-
diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml
new file mode 100644
index 00000000..87eadd71
--- /dev/null
+++ b/app/src/main/res/values-el-rGR/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Εφαρμογές Γρήγορης Εκκίνησης
+ Επιλέξτε εφαρμογές για γρήγορη εκκίνηση
+ Χώρος Παιχνιδιού
+ Διαχειριστείτε τις ρυθμίσεις παιχνιδιών σας
+
+ Επιλογές εντός του παιχνιδιού
+ Αποκλεισμός συμβάντος πλήρους οθόνης
+ Αποτροπή εμφάνισης συμβάντων πλήρους οθόνης όπως οι εισερχόμενες κλήσεις
+ Παραμονή σε λειτουργία
+ Χειρονομία κλειδώματος
+ Απενεργοποίηση αυτόματης φωτεινότητας
+ Απενεργοποιήστε τη χειρονομία ολίσθησης με τρία δάχτυλα
+ Απενεργοποίηση εντοπισμού σφαλμάτων USB
+ Επίπεδο αδιαφάνειας μενού επικάλυψης
+
+ Ειδοποιήσεις
+ Να μην εμφανίζεται
+ Εμφάνιση ως Αναδυόμενες ειδοποιήσεις
+ Εμφάνιση ως reTicker
+ Εμφάνιση ως Danmaku
+
+ Λειτουργία κουδουνίσματος
+ Αθόρυβο
+ Δόνηση
+ Κανονικό
+ Χωρίς αλλαγή
+
+ Βιβλιοθήκη
+ Προσθήκη
+ Διάλεξε το παιχνίδι σου
+ Αναζήτηση
+ Είστε βέβαιοι ότι θέλετε να αφαιρέσετε το %1$s από τη λίστα των παιχνιδιών σας;
+
+ Διαμόρφωση παιχνιδιού
+ Προτιμώμενη λειτουργία
+ Χρήση ANGLE (πειραματικό)
+ Χρήση του ANGLE renderer αντί των εγγενών προγραμμάτων οδήγησης GLES.\nΠΡΟΕΙΔΟΠΟΙΗΣΗ!! Μπορεί να χαλάσει τα γραφικά του παιχνιδιού, χρησιμοποιήστε με προσοχή!
+ Το ANGLE δεν είναι διαθέσιμο στο σύστημά σας
+ Αφαίρεση του %1$s από τη βιβλιοθήκη
+ Δεν υποστηρίζεται
+ Κανονικό
+ Επιδόσεις
+ Μπαταρία
+
+ Τιμή: %s
+ από προεπιλογή
+ Προεπιλεγμένη τιμή: %s\nΠατήστε παρατεταμένα για να ορίσετε
+ Η προεπιλεγμένη τιμή έχει οριστεί
+
+ Μπαταρία: %1$d%%
+ Διαθέσιμη μνήμη: %1$d\/%2$d MB
+
+ Λειτουργία
+ Πληροφορίες FPS
+ Απόκρυψη
+ Αναδυόμενες ειδοποιήσεις
+ reTicker
+ Danmaku
+ Ενεργοποιημένο
+ Απενεργοποιημένο
+ Προεπιλογή
+ Λειτουργία κλήσης
+ Καμία ενέργεια
+ Αυτόματη απάντηση
+ Αυτόματη απόρριψη
+ Λήφθηκε κλήση από %1$s
+ Απορρίφθηκε κλήση από %1$s
+
+ Λειτουργία ειδοποιήσεων Danmaku
+ Εμφάνιση ειδοποίησης ως danmaku άλλως κουκκίδα σχόλια ενώ το παιχνίδι είναι ενεργό
+ Ο Χώρος Παιχνιδιού εκτελείται
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml
new file mode 100644
index 00000000..40dba2b3
--- /dev/null
+++ b/app/src/main/res/values-es-rES/strings.xml
@@ -0,0 +1,114 @@
+
+
+
+ Aplicaciones de inicio rápido
+ Seleccionar aplicaciones para iniciar rápidamente
+ Espacio de Juego
+ Administra tu configuración de juegos
+
+ Opciones en el juego
+ Bloquear eventos en pantalla completa
+ Evitar la aparición de eventos en pantalla completa como llamadas entrantes
+ Permanecer encendido
+ Gesto de bloqueo
+ Desactivar brillo automático
+ Desactivar gesto de deslizar con tres dedos
+ Desactivar depuración USB
+ Nivel de opacidad del menú de superposición
+
+ Modo de notificación
+ No mostrar
+ Mostrar como notificaciones emergentes
+ Mostrar como reTicker
+ Mostrar como Danmaku
+
+ Modo de timbre
+ Silencio
+ Vibrar
+ Normal
+ No cambiar
+
+ Biblioteca
+ Añadir
+ Elige tu juego
+ Buscar
+ ¿Estás seguro de que quieres eliminar %1$s de tu biblioteca?
+
+ Configurar juego
+ Modo preferido
+ Usar nueva interfaz de usuario (experimental)
+ Utilizar renderizado ANGLE en lugar de controladores GLES nativos. \n¡ADVERTENCIA! Puede romper los gráficos de juegos, ¡Úsalo con cuidado!
+ ANGLE no está disponible en su sistema
+ Eliminar %1$s de la biblioteca
+ No soportado
+ Estándar
+ Rendimiento
+ Batería
+
+ Valor: %s
+ predeterminado
+ Valor predeterminado: %s\n
+Mantén presionado para establecer
+ Valor predeterminado establecido
+
+ Batería: %1$d%%
+ Memoria disponible: %1$d\/%2$d MB
+
+ Modo
+ Información de FPS
+ Ocultar
+ Notificaciones flotantes
+ reTicker
+ Danmaku
+ Activado
+ Desactivado
+ Predeterminado
+ Modo de llamada
+ Sin acción
+ Respuesta automática
+ Rechazo automático
+ Llamada recibida de %1$s
+ Llamada rechazada de %1$s
+
+ Modo notificación silenciosa
+ Mostrar notificación diseño circular mientras el juego está activo
+ El espacio del juego se está ejecutando
+
+ Llamada en ventana flotante
+ Usar ventana flotante compacta para responder o rechazar llamadas
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa-rIR/strings.xml
new file mode 100644
index 00000000..85d2377d
--- /dev/null
+++ b/app/src/main/res/values-fa-rIR/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ برنامههای شروع سریع
+ برنامهها را برای راهاندازی سریع انتخاب کنید
+ فضای بازی
+ تنظیمات بازی خود را مدیریت کنید
+
+ گزینه های درون بازی
+ مسدود کردن رویداد تمام صفحه
+ از نمایش رویدادهای تمام صفحه مانند تماس های دریافتی جلوگیری کنید
+ بیدار بمان
+ قفل کردن ژست
+ غیرفعالسازی روشنایی خودکار
+ حرکت تند کشیدن سه انگشت را غیرفعال کنید
+ غیرفعال کردن اشکال زدایی USB
+ سطح شفافیت منوی همپوشانی
+
+ حالت اعلانها
+ عدم نمایش
+ نمایش به صورت اعلان فوری
+ نمایش به صورت reTicker
+ نمایش به صورت Danmaku
+
+ حالت با صدا
+ سکوت
+ لرزش
+ معمولی
+ بدون تغییر
+
+ مجموعه
+ افزودن
+ بازی خود را انتخاب کنید
+ جستجو
+ آیا مطمئن هستید میخواهید %1$s را از فهرست بازیهای خود حذف کنید؟
+
+ پیکربندی بازی
+ حالت ترجیحی
+ استفاده از ANGLE (آزمایشی)
+ استفاده از رندر ANGLE به جای درایورهای GLES بومی، اگر دستگاه از آن پشتیبانی کند.\nهشدار!! ممکن است گرافیک بازی را خراب کند، با احتیاط استفاده کنید!
+ ANGLE در سیستم شما در دسترس نیست
+ %1$s را از مجموعه حذف کنید
+ پشتیبانی نشده
+ استاندارد
+ کارایی
+ باتری
+
+ ارزش: %s
+ به طور پیش فرض
+ ارزش پیشفرض: %s\n برای تنظیم نگه دارید
+ مقدار پیشفرض تعیین شده است
+
+ باتری: %1$d%%
+ حافظه موجود است: %1$d\/%2$d مگابایت
+
+ حالت
+ اطلاعات FPS
+ پنهان کردن
+ اعلان فوری
+ reTicker
+ Danmaku
+ فعال شد
+ غیرفعال شد
+ پيشفرض
+ حالت تماس
+ هیچ کاری انجام نده
+ پاسخگویی خودکار
+ رد دادن تماس
+ تماس دریافت شده از %1$s
+ تماس رد شده از %1$s
+
+ حالت اعلان گلوله جهنمی
+ در حالی که بازی فعال است، اعلان را به حالت اعلان گلوله جهنمی نشان دهید
+ فضای بازی در حال اجراست
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml
new file mode 100644
index 00000000..c50727df
--- /dev/null
+++ b/app/src/main/res/values-fi-rFI/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Quick Start Apps
+ Select apps to launch quickly
+ Game Space
+ Hallitse peliasetuksiasi
+
+ Pelin sisäiset asetukset
+ Estä koko näytön tapahtuma
+ Estää koko näytön tapahtumien, kuten saapuvien puhelujen näkymisen
+ Pysy hereillä
+ Lukitusele
+ Poista automaattinen kirkkaus käytöstä
+ Disable three fingers swipe gesture
+ Poista USB-vianetsintä käytöstä
+ Peittokuvavalikon läpinäkyvyystaso
+
+ Ilmoitustila
+ Älä näytä
+ Näytä Heads up
+ Näytä reTickerinä
+ Näytä Danmaku
+
+ Soittotila
+ Äänetön
+ Värinä
+ Normaali
+ Älä muuta
+
+ Peliluettelo
+ Lisää
+ Valitse pelisi
+ Etsi
+ Oletko varma, että haluat poistaa %1$s peliluettelostasi?
+
+ Määritä peli
+ Ensisijainen tila
+ Käytä ANGLE (kokeellinen)
+ ANGLE-renderöijän käyttäminen natiivien GLES-ajurien sijaan.\nVAROITUS!!! Saattaa rikkoa pelin grafiikkaa, käytä varoen!
+ ANGLE ei ole käytettävissä järjestelmässäsi
+ Poista %1$s peliluettelosta
+ Ei tuettu
+ Vakio
+ Suorituskyky
+ Akku
+
+ Arvo: %s
+ oletuksena
+ Oletusarvo: %s\nAseta napauttamalla pitkään
+ Oletusarvo asetettu
+
+ Akku: %1$d%%
+ Käytettävissä oleva muisti: %1$d\/%2$d MB
+
+ Tila
+ FPS-tiedot
+ Piilota
+ Leijuvat ilmoitukset
+ reTicker
+ Danmaku
+ Käytössä
+ Pois käytöstä
+ Default
+ Call mode
+ No action
+ Auto answer
+ Auto reject
+ Received call from %1$s
+ Rejected call from %1$s
+
+ Danmaku Notification mode
+ Show notification as danmaku aka bullet comments while game is active
+ Game Space is running
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml
new file mode 100644
index 00000000..a1861d22
--- /dev/null
+++ b/app/src/main/res/values-fr-rFR/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Applications de démarrage rapide
+ Sélectionnez les applications à lancer rapidement
+ Espace Jeux
+ Gérez votre configuration de jeu
+
+ Options en jeu
+ Bloquer les évènements plein écran
+ Empêcher les événements plein écran comme montrer les appels entrants
+ Rester éveillé
+ Gestes de verrouillage
+ Désactiver la luminosité automatique
+ Désactiver le geste de balayage à trois doigts
+ Désactiver le débogage USB
+ Niveau d\'opacité du menu de superposition
+
+ Mode notification
+ Ne pas afficher
+ Afficher en notification flottante
+ Afficher comme reTicker
+ Afficher comme Danmaku
+
+ Mode sonnerie
+ Silencieux
+ Vibreur
+ Normal
+ Ne pas changer
+
+ Bibliothèque
+ Ajouter
+ Choisissez votre jeu
+ Rechercher
+ Êtes-vous sûr de vouloir supprimer %1$s de votre bibliothèque ?
+
+ Configurer le jeu
+ Mode préféré
+ Utiliser ANGLE (expérimental)
+ Utiliser le moteur de rendu ANGLE au lieu des pilotes GLES natifs.\nATTENTION!! Peut casser le rendu graphique des jeux, à utiliser avec précaution !
+ ANGLE n\'est pas disponible pour votre système
+ Retirer %1$s de la bibliothèque
+ Non-supporté
+ Standard
+ Performance
+ Batterie
+
+ Valeur : %s
+ par défaut
+ Valeur par défaut : %s\nRester appuyé pour définir
+ Valeur par défaut définie
+
+ Batterie : %1$d%%
+ Mémoire disponible : %1$d\/%2$d Mo
+
+ Mode
+ Infos FPS
+ Masquer
+ Notification flotante
+ reTicker
+ Danmaku
+ Activé
+ Désactivé
+ Par défaut
+ Mode d\'appels
+ Pas d\'action
+ Décrochage automatique
+ Raccrochage automatique
+ Appel reçu de %1$s
+ Appel de %1$s rejeté
+
+ Mode de notification Danmaku
+ Afficher une notification en tant que danmaku (les commentaires flottants) lorsque le jeu est actif
+ Espace de Jeux en cours de fonctionnement
+
+ Superposition d\'appels
+ Afficher la surcouche d\'appel minimale pour répondre/rejeter les appels
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml
new file mode 100644
index 00000000..9a68d251
--- /dev/null
+++ b/app/src/main/res/values-hu-rHU/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Gyorsindítási alkalmazások
+ Válassza ki a gyorsan indítandó alkalmazásokat
+ Játéktér
+ Játékbeállítások kezelése
+
+ Játékon belüli lehetőségek
+ Teljes képernyős mód blokkolása
+ Teljes képernyős események, mint például a bejövő hívás megjelenítésének megakadályozása
+ Ne zárja le a képernyőt
+ Gesztusok gátlása
+ Az automatikus fényerőszabályzás tiltása
+ Három ujjas húzási gesztus letiltása
+ Az USB-hibakeresés tiltása
+ Átfedés menü átlátszósági szintje
+
+ Értesítési mód
+ Ne jelenjen meg
+ Felugró értesítés
+ Megjelenítés mint reTicker
+ Mutasd mint Danmaku
+
+ Csengés mód
+ Néma
+ Rezgő
+ Normál
+ Ne változtassa meg
+
+ Könyvtár
+ Hozzáad
+ Válaszd ki a játékod
+ Keresés
+ Biztos vagy benne, hogy el akarod távolítani a(z) %1$s-t a játéklistádról?
+
+ Játék konfigurálása
+ Preferált mód
+ ANGLE használata (kísérleti)
+ ANGLE renderelő használata a natív GLES illesztőprogramok helyett.\nFIGYELEM!!! Elronthatja a játék grafikáját, óvatosan használd!
+ ANGLE nem elérhető ezen a rendszeren
+ %1$s eltávolítása a könyvtáradból
+ Nem támogatott
+ Általános
+ Teljesítmény
+ Akkumulátor
+
+ Érték: %s
+ alapértelmezés szerint
+ Alapértelmezett érték: %s\nHosszú koppintás a beállításhoz
+ Az alapértelmezett érték beállítva
+
+ Akkumulátor: %1$d%%
+ Elérhető memória: %1$d\/%2$d MB
+
+ Mód
+ FPS-adatok
+ Elrejt
+ Lebegő értesítés
+ reTicker
+ Danmaku
+ Engedélyezve
+ Letiltva
+ Alapértelmezett
+ Hívás mód
+ Nincs művelet
+ Automata válasz
+ Automata elutasítás
+ Hívás fogadva %1$s-tól
+ Hívás elutasítva %1$s-tól
+
+ Danmaku Értesítő mód
+ Értesítések danmakuként mutatása, avagy kommentek kilövése játék mód közben
+ A Játéktér fut
+
+ Hívás átfedés
+ Minimális hívásfelületet jelenít meg a hívások fogadásához/elutasításához
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml
new file mode 100644
index 00000000..18a05882
--- /dev/null
+++ b/app/src/main/res/values-in-rID/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Aplikasi Mulai Cepat
+ Pilih aplikasi untuk diluncurkan dengan cepat
+ Ruang Game
+ Kelola pengaturan game Anda
+
+ Opsi dalam game
+ Blokir acara layar penuh
+ Cegah acara layar penuh seperti panggilan masuk muncul saat dalam game
+ Tetap terjaga
+ Kunci gestur
+ Nonaktifkan kecerahan otomatis
+ Matikan gerakan geser tiga jari
+ Nonaktifkan USB debugging
+ Tingkat opasitas hamparan menu
+
+ Mode notifikasi
+ Jangan tampilkan
+ Muncul sebagai Notifikasi Mengambang
+ Muncul sebagai reTicker
+ Muncul sebagai Danmaku
+
+ Mode dering
+ Senyap
+ Getar
+ Normal
+ Jangan diubah
+
+ Pustaka
+ Tambah
+ Pilih game Anda
+ Telusuri
+ Anda yakin ingin menghapus %1$s dari daftar game Anda?
+
+ Konfigurasi game
+ Mode pilihan
+ Gunakan ANGLE (eksperimental)
+ Menggunakan perender ANGLE sebagai ganti driver GLES asli.\nPERINGATAN! Dapat merusak grafik game, gunakan dengan hati-hati!
+ ANGLE tidak tersedia di sistem Anda
+ Hapus %1$s dari pustaka
+ Tidak didukung
+ Standar
+ Kinerja
+ Baterai
+
+ Nilai: %s
+ bawaan
+ Nilai bawaan: %s\nTekan lama untuk menerapkan
+ Nilai bawaan telah diterapkan
+
+ Baterai: %1$d%%
+ Memori tersedia: %1$d\/%2$d MB
+
+ Mode
+ Info FPS
+ Sembunyikan
+ Notifikasi mengambang
+ reTicker
+ Danmaku
+ Diaktifkan
+ Dinonaktifkan
+ Bawaan
+ Mode panggilan
+ Tidak ada tindakan
+ Jawab otomatis
+ Tolak otomatis
+ Menerima panggilan dari %1$s
+ Menolak panggilan dari %1$s
+
+ Mode Pemberitahuan Danmaku
+ Tampilkan notifikasi sebagai danmaku alias komentar bullet saat permainan aktif
+ Game Space sedang berjalan
+
+ Overlay panggilan
+ Tampilkan overlay panggilan minimal untuk menjawab/menolak panggilan
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
deleted file mode 100644
index c530e980..00000000
--- a/app/src/main/res/values-in/strings.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
- Game Space
- Kelola pengaturan permainan Anda
- Pilih permainan Anda
- Nonaktifkan kecerahan otomatis
- Jaga kecerahan tetap stabil saat dalam permainan
- Nonaktifkan notifikasi mengambang
- Nonaktifkan pemberitahuan notifikasi mengambang saat dalam permainan
- Daftar permainan
- Anda yakin ingin menghapus %1$s dari daftar permainan Anda?
- Cari
- Nonaktifkan sementara gerakan usap tiga jari untuk tangkapan layar saat dalam permainan
- Nonaktifkan gerakan usap untuk tangkapan layar
- chaldeaprjkt
- aktifkan
- nonaktifkan
-
- Mode
-
- - Tidak didukung
- - Standar
- - Performa
- - Baterai
-
- Notifikasi mengambang
- Info FPS
- Tetap terbangun
- Jaga agar layar tetap terbangun saat dalam permainan
-
- Mode dering dalam permainan
-
- - Diam
- - Getar
- - Normal
-
-
- Blokir acara layar penuh
- Cegah acara layar penuh seperti panggilan masuk muncul saat dalam permainan
-
- Konfigurasi Permainan
- Mode Pilihan
-
- - Standar
- - Performa
- - Baterai
-
-
- Gunakan ANGLE (percobaan)
- Menggunakan perender ANGLE sebagai pengganti driver GLES asli.\nWARNING!! Dapat merusak grafik permainan, gunakan dengan hati-hati!
- ANGLE tidak tersedia di sistem Anda
-
- Hapus %1$s dari daftar
-
-
diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml
new file mode 100644
index 00000000..06f5e7b1
--- /dev/null
+++ b/app/src/main/res/values-it-rIT/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ App di avvio rapido
+ Seleziona le app da avviare rapidamente
+ Spazio di gioco
+ Gestisci la tua configurazione di gioco
+
+ Opzioni di gioco
+ Blocca evento a schermo intero
+ Evitare la comparsa di eventi a schermo intero come le chiamate in arrivo
+ Resta attivo
+ Blocca gesto
+ Disabilita luminosità automatica
+ Disabilita il gesto di scorrimento a tre dita
+ Disabilita debug USB
+ Livello di opacità menù sovrapposizione
+
+ Modalità notifica
+ Non visualizzare
+ Mostra come notifiche a comparsa
+ Mostra come reTicker
+ Mostra come Danmaku
+
+ Modalità suoneria
+ Silenzioso
+ Vibrazione
+ Normale
+ Non modificare
+
+ Libreria
+ Aggiungi
+ Scegli il tuo gioco
+ Cerca
+ Sei sicuro di voler rimuovere %1$s dalla tua lista dei giochi?
+
+ Configura gioco
+ Modalità preferita
+ Usa nuova interfaccia (sperimentale)
+ Usando il renderer ANGLE invece dei driver nativi GLES.\nATTENZIONE!! Potrebbe rompere la grafica del gioco, usare con cautela!
+ ANGLE non è disponibile sul tuo sistema
+ Rimuovi %1$s dalla libreria
+ Non supportato
+ Predefinito
+ Prestazioni
+ Batteria
+
+ Valore: %s
+ per impostazione predefinita
+ Valore predefinito: %s\nTocca a lungo per impostare
+ Valore predefinito impostato
+
+ Batteria: %1$d%%
+ Memoria disponibile: %1$d\/%2$d MB
+
+ Modalità
+ Info FPS
+ Nascondi
+ Notifiche a comparsa
+ reTicker
+ Danmaku
+ Abilitato
+ Disabilitato
+ Predefinito
+ Modalità chiamata
+ Nessuna azione
+ Risposta automatica
+ Rifiuto automatico
+ Chiamata ricevuta da %1$s
+ Chiamata rifiutata da %1$s
+
+ Modalità notifica Danmaku
+ Mostra la notifica come Danmaku, ovvero i commenti sui proiettili, mentre il gioco è attivo
+ GameSpace è in esecuzione
+
+ Overlay chiamata
+ Mostra la sovrapposizione minima delle chiamate per rispondere/rifiutare le chiamate
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw-rIL/strings.xml
new file mode 100644
index 00000000..460be05a
--- /dev/null
+++ b/app/src/main/res/values-iw-rIL/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Quick Start Apps
+ Select apps to launch quickly
+ מרכז משחקים
+ נהל את הגדרות המשחק שלך
+
+ הגדרות משחקים
+ חסום התראות קופצות במסך מלא
+ חסום התראות קופצות במסך מלא כולל שיחות טלפון
+ השאר פועל
+ נעל מחוות
+ בטל בהירות אוטומטית
+ Disable three fingers swipe gesture
+ למנוע איתור באגים
+ Overlay menu opacity level
+
+ מצב התראה
+ אל תראה
+ הצג כ Heads up
+ הצג כ reTicker
+ הצג כ Danmaku
+
+ מצב צלצול
+ שקט
+ רטט
+ רגיל
+ ללא שינוי
+
+ ספריה
+ הוסף
+ בחר משחק
+ חיפוש
+ האם אתה בטוח שאתה רוצה להסיר את %1$s מרשימת המשחקים?
+
+ הגדרות משחק
+ מצב מועדף
+ Use ANGLE (experimental)
+ Using ANGLE renderer instead of native GLES drivers.\nWARNING!! May breaks game graphics, use with caution!
+ ANGLE is not available on your system
+ הסר את %1$s מהספריה
+ לא נתמך
+ סטנדרטי
+ ביצועים
+ סוללה
+
+ ערך: %s
+ כברירת מחדל
+ ברירת מחדל %s\n. לחיצה ממושכת להגדרה
+ ערך ברירת מחדל מוגדר
+
+ סוללה: %1$d%%
+ זכרון זמין: %1$d%2$d MB
+
+ מצב
+ מידע על FPS
+ הסתר
+ Heads Up
+ reTicker
+ Danmaku
+ מופעל
+ מושבת
+ ברירת המחדל
+ מצב שיחות
+ ללא פעולה
+ מענה אוטומטי
+ דחיה אוטומטית של השיחה
+ קבל שיחות מ%1$s
+ דחה שיחות מ%1$s
+
+ מצב התראה Danmaku
+ Show notification as danmaku aka bullet comments while game is active
+ Game Space is running
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml
new file mode 100644
index 00000000..53f71bfb
--- /dev/null
+++ b/app/src/main/res/values-ja-rJP/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ クイックスタートするアプリ
+ 素早く起動するアプリを選択
+ ゲームスペース
+ ゲームの設定を管理
+
+ ゲーム内オプション
+ 全画面表示イベントをブロック
+ ゲーム中は着信通話のような全画面イベントが表示されないようにする
+ 常に画面点灯
+ ジェスチャーをロック
+ 自動明るさ調節を無効化
+ 3本指スワイプジェスチャーを無効化
+ USB デバッグを無効化
+ オーバーレイメニューの不透明度
+
+ 通知モード
+ 表示しない
+ ポップアップ表示する
+ reTicker として表示
+ Danmaku として表示
+
+ 着信音モード
+ サイレント
+ バイブレーション
+ 標準
+ 変更しない
+
+ ライブラリ
+ 追加
+ ゲームを選択
+ 検索
+ ゲームリストから%1$s を削除しますか?
+
+ ゲーム設定
+ 優先モード
+ ANGLE を使用 (実験的)
+ ネイティブ GLES ドライバーの代わりに ANGLE レンダラーを使用します。\n警告! ゲームグラフィックが破損する可能性があります。注意して使用して下さい!
+ お使いのシステムでは ANGLE は利用できません
+ %1$s をライブラリから削除
+ 非対応
+ 標準
+ パフォーマンス優先
+ バッテリー優先
+
+ 値: %s
+ 既定
+ 既定値: %s\n長押しで設定
+ 既定値が設定されています
+
+ バッテリー: %1$d%%
+ 利用可能メモリ: %1$d\/%2$d MB
+
+ モード
+ FPS 情報
+ 非表示にする
+ ポップアップ通知
+ reTicker
+ Danmaku
+ 有効
+ 無効
+ デフォルト
+ 着信モード
+ なし
+ 自動応答
+ 自動拒否
+ %1$s からの着信を受信しました
+ %1$s からの着信を拒否しました
+
+ 弾幕通知モード
+ ゲーム中に弾幕コメントとして通知を表示する
+ ゲームスペースが実行中です
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml
new file mode 100644
index 00000000..2c8b5e9f
--- /dev/null
+++ b/app/src/main/res/values-ko-rKR/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Quick Start Apps
+ Select apps to launch quickly
+ 게임 스페이스
+ 게임용 설정 관리
+
+ 인게임 옵션
+ 전체 화면 이벤트 방지
+ 걸려오는 전화 등 전체 화면 이벤트가 열리는 것을 방지합니다.
+ 화면 계속 켜 두기
+ 제스처 잠금
+ 자동 밝기 사용 안함
+ 세 손가락 쓸기 제스처 사용 안함
+ USB 디버깅 사용 안함
+ 오버레이 메뉴 불투명도
+
+ 알림 모드
+ 표시 안함
+ 헤드업으로 표시
+ reTicker로 표시
+ 탄막으로 표시
+
+ 벨소리 모드
+ 무음
+ 진동
+ 소리
+ 바꾸지 않음
+
+ 라이브러리
+ 추가
+ 게임 선택
+ 검색
+ 정말 게임 목록에서 %1$s 앱을 제거하시겠습니까?
+
+ 게임 구성 설정
+ 선호 모드
+ ANGLE 사용(실험적)
+ 기본 GLES 드라이버 대신 ANGLE 렌더러를 사용합니다.\n경고! 게임 그래픽이 깨질 수 있습니다. 주의해서 사용하세요!
+ 이 시스템에서 ANGLE 드라이버를 사용할 수 없습니다.
+ 라이브러리에서 %1$s 제거
+ 지원 안함
+ 기본
+ 성능
+ 배터리
+
+ 값: %s
+ 기본값
+ 기본값: %s\n길게 누르면 기본값으로 초기화합니다.
+ 기본값으로 초기화했습니다.
+
+ 배터리: %1$d%%
+ 가용 메모리: %1$d\/%2$dMB
+
+ 모드
+ FPS 정보
+ 숨기기
+ 헤드업
+ reTicker
+ 탄막
+ 켜짐
+ 꺼짐
+ 기본값
+ 전화 모드
+ 작업 없음
+ 자동으로 받기
+ 자동으로 거부
+ %1$s 번호에서 오는 전화 받기
+ %1$s 번호에서 오는 전화 거부
+
+ 탄막 알림 모드
+ 게임 중일 때 알림을 탄막처럼 작게 표시
+ Game Space is running
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml
index 26e87d8c..c874e7a8 100644
--- a/app/src/main/res/values-night/colors.xml
+++ b/app/src/main/res/values-night/colors.xml
@@ -8,4 +8,12 @@
@android:color/system_neutral1_50
@android:color/system_neutral1_50
@android:color/system_neutral2_100
+
+ @android:color/system_neutral1_900
+ @android:color/system_neutral1_900
+ @android:color/system_accent1_100
+ @android:color/system_accent1_100
+ @android:color/system_accent2_50
+ @android:color/system_neutral1_1000
+ @android:color/system_neutral1_0
diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml
new file mode 100644
index 00000000..7225ed1d
--- /dev/null
+++ b/app/src/main/res/values-nl-rNL/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Quick Start Apps
+ Select apps to launch quickly
+ Game ruimte
+ Beheer uw gaming-instellingen
+
+ In-game opties
+ Blokkeer volledig scherm event
+ Voorkom dat volledig scherm events zoals inkomende oproepen worden weergegeven
+ Blijf wakker
+ Vergrendel gebaar
+ Automatische helderheid uitschakelen
+ Disable three fingers swipe gesture
+ Usb-foutopsporing uitschakelen
+ Transparantieniveau van overlappingsmenu
+
+ Notificatie modus
+ Niet tonen
+ Heads-up tonen
+ Toon als reTicker
+ Weergeven als Danmaku
+
+ Beltoonmodus
+ Stil
+ Trillen
+ Normaal
+ Niet wijzigen
+
+ Bibliotheek
+ Toevoegen
+ Kies je spel
+ Zoeken
+ Weet je zeker dat je %1$s uit je bibliotheek wilt verwijderen?
+
+ Spel configureren
+ Voorkeursmodus
+ Gebruik ANGLE (experimenteel)
+ Gebruik ANGLE renderer in plaats van oorspronkelijke GLES drivers.\nWAARSCHUWING!! Kan spel afbeeldingen breken, gebruik met voorzichtigheid!
+ ANGLE is niet beschikbaar op uw systeem
+ Verwijder %1$s uit bibliotheek
+ Niet ondersteund
+ Standaard
+ Prestatie
+ Batterij
+
+ Waarde: %s
+ standaard
+ Standaard waarde: %s\nLang indrukken om in te stellen
+ Standaard waarde is ingesteld
+
+ Batterij: %1$d%%
+ Geheugen beschikbaar: %1$d\/%2$d MB
+
+ Modus
+ FPS info
+ Verbergen
+ Pop-up
+ reTicker
+ Danmaku
+ Ingeschakeld
+ Uitgechakeld
+ Standaard
+ Oproepmodus
+ Geen actie
+ Auto antwoord
+ Automatisch afwijzen
+ Oproep ontvangen van %1$s
+ Oproep van %1$s afgewezen
+
+ Danmaku meldingsmodus
+ Melding weergeven als danmaku aka bullet reacties wanneer het spel actief is
+ Game Space is running
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-no-rNO/strings.xml b/app/src/main/res/values-no-rNO/strings.xml
new file mode 100644
index 00000000..12a6e565
--- /dev/null
+++ b/app/src/main/res/values-no-rNO/strings.xml
@@ -0,0 +1,87 @@
+
+
+
+ Game Space
+ Manage your gaming setup
+
+ In-game options
+ Block fullscreen event
+ Prevent fullscreen events like incoming calls from appearing
+ Stay awake
+ Lock gesture
+ Disable auto-brightness
+ Disable three fingers swipe gesture
+ Disable USB debugging
+ Overlay menu opacity level
+
+ Notification mode
+ Do not show
+ Show as Heads Up
+ Show as reTicker
+ Show as Danmaku
+
+ Ringer mode
+ Silent
+ Vibrate
+ Normal
+ Do not change
+
+ Library
+ Add
+ Pick your game
+ Search
+ Are you sure you want to remove %1$s from your game list?
+
+ Configure game
+ Preferred mode
+ Use ANGLE (experimental)
+ Using ANGLE renderer instead of native GLES drivers.\nWARNING!! May breaks game graphics, use with caution!
+ ANGLE is not available on your system
+ Remove %1$s from library
+ Unsupported
+ Standard
+ Performance
+ Battery
+
+ Value: %s
+ by default
+ Default value: %s\nLong tap to set
+ Default value is set
+
+ Battery: %1$d%%
+ Memory available: %1$d\/%2$d MB
+
+ Mode
+ FPS info
+ Hide
+ Heads Up
+ reTicker
+ Danmaku
+ Enabled
+ Disabled
+ Default
+ Call mode
+ No action
+ Auto answer
+ Auto reject
+ Received call from %1$s
+ Rejected call from %1$s
+
+ Danmaku Notification mode
+ Show notification as danmaku aka bullet comments while game is active
+
diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml
new file mode 100644
index 00000000..512d247c
--- /dev/null
+++ b/app/src/main/res/values-pl-rPL/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Aplikacje szybkiego startu
+ Wybierz aplikacje do szybkiego uruchamiania
+ Przestrzeń gier
+ Zarządzaj konfiguracją gier
+
+ Opcje w grze
+ Zablokuj wydarzenie na pełnym ekranie
+ Zapobiegaj pojawianiu się wydarzeń na pełnym ekranie, takich jak połączenia przychodzące
+ Pozostaw ekran włączony
+ Gest blokady
+ Wyłącz automatyczną jasność
+ Wyłącz gest przesuwania trzema palcami
+ Wyłącz debugowanie USB
+ Poziom przezroczystości nakładki menu
+
+ Opcje powiadomień
+ Nie pokazuj
+ Wyświetl jako wyskakujące powiadomienia
+ Pokaż jako reTicker
+ Pokaż jako pasek Danmaku
+
+ Tryb dzwonka
+ Tryb cichy
+ Wibracje
+ Normalny
+ Nie zmieniaj
+
+ Biblioteka
+ Dodaj
+ Wybierz swoją grę
+ Szukaj
+ Czy na pewno chcesz usunąć %1$s z listy gier?
+
+ Skonfiguruj grę
+ Preferowany tryb
+ Użyj ANGLE (eksperymentalne)
+ Używaj renderowania ANGLE zamiast natywnych sterowników GLES.\nOSTRZEŻENIE!! Może uszkodzić grafikę gry, używaj z ostrożnością!
+ ANGLE nie jest dostępne w twoim systemie
+ Usuń %1$s z biblioteki
+ Nieobsługiwane
+ Standardowy
+ Wydajność
+ Bateria
+
+ Wartość: %s
+ domyślnie
+ Wartość domyślna: %s\nPrzytrzymaj, aby ustawić
+ Wartość domyślna jest ustawiona
+
+ Bateria: %1$d%%
+ Dostępna pamięć: %1$d\/%2$d MB
+
+ Tryb
+ Informacja o FPS
+ Ukryj
+ Wyskakujące powiadomienia
+ reTicker
+ Danmaku
+ Włączono
+ Wyłączono
+ Domyślnie
+ Tryb połączeń
+ Brak akcji
+ Automatyczne odbieranie
+ Automatyczne odrzucanie
+ Odebrano połączenie od %1$s
+ Odrzucono połączenie od %1$s
+
+ Tryb powiadomień Danmaku
+ Wyświetlaj powiadomienie jako Danmaku w postaci wypunktowanych komentarzy, gdy gra jest aktywna
+ Przestrzeń gier jest uruchomiona
+
+ Nakładka połączenia
+ Pokazuj minimalną nakładkę podczas odbierania/odrzucania połączeń telefonicznych
+
+ Uruchom optymalizację
+ Uruchom przyspieszenie
+ Zoptymalizuj wykorzystanie procesora i pamięci, aby gra uruchamiała się szybciej
+ Inteligentne zarządzanie pamięcią
+ Automatycznie zamykaj aplikacje działające w tle podczas uruchamiania gier
+ Ładowanie priorytetowe
+ Ustaw priorytet zasobów podczas uruchamiania gry
+ Zarządzanie pamięcią podręczną
+ Optymalizuj pamięć podręczną gry dla szybszego ładowania
+
+ - Zrównoważone (zalecane)
+ - Maksymalna wydajność
+ - Oszczędność baterii
+
+
+ - zrównoważone
+ - wydajność
+ - oszczędzanie energii
+
+
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 00000000..e32cac2b
--- /dev/null
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Aplicativos de início rápido
+ Selecione Aplicativos para o Início Rápido
+ Espaço de Jogos
+ Gerencie sua configuração de jogos
+
+ Opções do jogo
+ Bloquear eventos em tela cheia
+ Impedir que eventos em tela cheia como chamadas recebidas apareçam
+ Permanecer ativo
+ Bloquear gestos
+ Desativar brilho automático
+ Desativar gesto de deslizar três dedos
+ Desativar depuração USB
+ Nível de opacidade do menu de opções
+
+ Estilo das notificações
+ Não exibir
+ Mostrar como notificação flutuante
+ Mostrar como reTicker
+ Mostrar como Danmaku
+
+ Modo de toque
+ Silencioso
+ Vibrar
+ Normal
+ Não mudar
+
+ Biblioteca
+ Adicionar
+ Escolha seu jogo
+ Pesquisa
+ Tem certeza de que deseja remover %1$s da sua lista de jogos?
+
+ Configurar jogo
+ Modo preferencial
+ Usar ANGLE (experimental)
+ Usando renderizador ANGLE em vez de drivers GLES nativos.\nAVISO!! Pode quebrar gráficos do jogo, use com cuidado!
+ ANGLE não está disponível no seu sistema
+ Remover %1$s da biblioteca
+ Incompatível
+ Padrão
+ Desempenho
+ Bateria
+
+ Valor: %s
+ valor padrão
+ Valor padrão: %s\nToque longo para definir
+ Valor padrão definido
+
+ Bateria: %1$d%%
+ Memória disponível: %1$d\/%2$d MB
+
+ Modo
+ Informações de FPS
+ Ocultar
+ Notificações flutuantes
+ reTicker
+ Danmaku
+ Ativado
+ Desativado
+ Padrão
+ Modo de chamada
+ Nenhuma ação
+ Atender automaticamente
+ Recusar automaticamente
+ Chamada recebida de %1$s
+ Chamada recusada de %1$s
+
+ Modo de notificação Danmaku
+ Mostrar notificações como balões de comentários durante o jogo
+ Espaço de jogo em execução
+
+ Sobreposição de chamada
+ Mostrar sobreposição de chamada mínima para atender/rejeitar chamadas
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml
new file mode 100644
index 00000000..d0ad001e
--- /dev/null
+++ b/app/src/main/res/values-pt-rPT/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Inicialização rápida de aplicativos
+ Selecione as apps para iniciar rapidamente
+ Espaço de jogo
+ Gerir a sua configuração de jogos
+
+ Opções do jogo
+ Bloquear eventos em ecrã inteiro
+ Impedir que ocorram eventos em ecrã inteiro, como receber chamadas
+ Manter ativo
+ Bloquear gestos
+ Desativar brilho automático
+ Desativar gesto de deslizar três dedos
+ Desativar depuração USB
+ Transparência do menu de sobreposição
+
+ Modo de notificação
+ Não mostrar
+ Mostrar como notificação flutuante
+ Mostrar como reTicker
+ Mostrar como Danmaku
+
+ Modo de toque
+ Silencioso
+ Vibrar
+ Normal
+ Não mudar
+
+ Biblioteca de jogos
+ Adicionar
+ Escolha o seu jogo
+ Procurar
+ Tem certeza de que deseja remover %1$s da sua biblioteca?
+
+ Configurar jogo
+ Modo preferido
+ Usar ANGLE (experimental)
+ A usar o renderizador ANGLE em vez de controladores GLES nativos.\nAVISO!! Pode quebrar os gráficos do jogo, use com cuidado!
+ ANGLE não está disponível no seu sistema
+ Remover %1$s da biblioteca
+ Não suportado
+ Padrão
+ Desempenho
+ Bateria
+
+ Valor: %s
+ padrão
+ Valor padrão: %s\nO Prima para definir
+ O valor padrão está definido
+
+ Bateria: %1$d%%
+ Memória disponível: %1$d\/%2$d MB
+
+ Modo
+ Info. de FPS
+ Ocultar
+ Notificações flutuantes
+ reTicker
+ Danmaku
+ Ativado
+ Desativado
+ Predefinido
+ Modo de chamada
+ Nenhuma ação
+ Resposta automática
+ Rejeitar automaticamente
+ Chamada de %1$s recebida
+ Chamada de %1$s rejeitada
+
+ Modo de notificação Danmaku
+ Mostrar notificações enquanto o jogo estiver aberto
+ Espaço de Jogo a ser executado
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml
new file mode 100644
index 00000000..c256d45f
--- /dev/null
+++ b/app/src/main/res/values-ro-rRO/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Pornire rapidă a aplicațiilor
+ Selectați aplicațiile pentru lansare rapidă
+ Spațiu de jocuri
+ Gestionează-ți configurarea jocurilor
+
+ Opțiuni în joc
+ Blocare eveniment pe tot ecranul
+ Împiedicați apariția evenimentelor de pe tot ecranul, cum ar fi apelurile primite
+ Menține ecranul activ
+ Blochează gesturile
+ Dezactivează luminozitatea automată
+ Dezactivează gestul de trei degete
+ Dezactivează depanarea USB
+ Opacitate pentru meniul suprapus
+
+ Modul notificare
+ Nu se afișează
+ Arată ca atenționare
+ Arată ca reTicker
+ Arată ca Danmaku
+
+ Mod sonerie
+ Silențios
+ Vibrații
+ Normal
+ Nu schimba
+
+ Bibliotecă
+ Adaugă
+ Alege-ți numele
+ Căutare
+ Ești sigur că vrei să ștergi %1$s din lista ta de jocuri?
+
+ Configurare joc
+ Mod preferat
+ Utilizează ANGLE (experimental)
+ Folosind redare ANGLE în locul driverelor GLES nativi.\nATENȚIE!! Poate strica aspectul jocului, folosește cu prudență!
+ ANGLE nu este disponibil pe sistemul dumneavoastră
+ Elimină %1$s din bibliotecă
+ Necompatibil
+ Standard
+ Performanță
+ Baterie
+
+ Valoare: %s
+ implicit
+ Valoare implicită: %s\nAtingeți lung pentru a seta
+ Valoarea implicită este setată
+
+ Baterie: %1$d%%
+ Memorie disponibilă: %1$d\/%2$d MB
+
+ Mod
+ Informații FPS
+ Ascunde
+ Atenționări
+ reTicker
+ Danmaku
+ Activat
+ Dezactivat
+ Prestabilit
+ Mod apel
+ Nicio acțiune
+ Răspuns automat
+ Respingere automată
+ Apel primit de la %1$s
+ Apel respins de la %1$s
+
+ Mod notificări Danmaku
+ Arată notificarea ca și comentariile de tip glonț aka glonț cât timp jocul este activ
+ Spațiul de joc rulează
+
+ Apel suprapus
+ Afișați suprapunerea minimă a apelurilor pentru a răspunde/respinge apelurile
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml
new file mode 100644
index 00000000..be42520d
--- /dev/null
+++ b/app/src/main/res/values-ru-rRU/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Быстрый запуск приложений
+ Выберите приложения для быстрого запуска
+ Поиграем?
+ Настройка игровых возможностей
+
+ Настройки игры
+ Блокировать полноэкранные события
+ Предотвращение появления полноэкранных событий, таких как входящие вызовы
+ Не засыпать
+ Блокировать жесты
+ Отключить автояркость
+ Отключить жест тремя пальцами
+ Отключить отладку по USB
+ Уровень прозрачности панели
+
+ Режим уведомлений
+ Не показывать
+ Всплывающие уведомления
+ Новый стиль уведомлений
+ Прозрачные без фона
+
+ Режим звонка в игре
+ Беззвучный
+ Вибрация
+ Обычный
+ Не изменять
+
+ Библиотека
+ Добавить
+ Выберите игру
+ Поиск
+ Вы действительно хотите удалить %1$s из своего списка игр?
+
+ Настроить игру
+ Предпочтительный режим
+ Использовать ANGLE (эксперементально)
+ Использование отрисовку ANGLE вместо собственных драйверов GLES.\nВНИМАНИЕ!! Может ломать игровую графику, использовать с осторожностью!
+ ANGLE недоступен в вашей системе
+ Удалить %1$s из библиотеки
+ Не поддерживается
+ Стандартный
+ Производительный
+ Батарея
+
+ Значение: %s
+ по умолчанию
+ Значение по умолчанию: %s\nУдерживайте для установки
+ Значение по умолчанию установлено
+
+ Батарея: %1$d%%
+ Доступная память: %1$d\/%2$d MB
+
+ Режим
+ кадр/сек
+ Скрыть
+ Всплывающее уведомление
+ Новый стиль уведомлений
+ Прозрачные без фона
+ Включено
+ Отключено
+ По умолчанию
+ Режим вызова
+ Без действия
+ Автоответ
+ Автосброс
+ Поступил звонок от %1$s
+ Отклонён вызов от %1$s
+
+ Режим прозрачных уведомлений
+ Показывать уведомление в виде прозрачных комментариев, пока игра активна
+ Игровое пространство запущено
+
+ Уведомление о вызове
+ Показывать минимальное уведомление о звонке для ответа/отклонения вызова
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
deleted file mode 100644
index 758fa062..00000000
--- a/app/src/main/res/values-ru/strings.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-
-
-
- Game Space
- Управляйте игровыми настройками
- Выберите свою игру
- Отключить авто-яркость
- Не менять яркость пока вы в игре
- Отключить уведомления
- Отключить всплывающие уведомления пока вы в игре
- Библиотека
- Вы уверены, что хотите удалить %1$s из своей библиотеки?
- Поиск
- Временно отключить жест тремя пальцами для скриншота во время игры.
- Отключить свайп для скриншота
- chaldeaprjkt
- включено
- отключено
-
- Режим
-
- - Не поддерживается
- - Баланс
- - Скорость
- - Экономия
-
- Уведомления
- Отображать FPS
- Не отключать экран
- Не отключать экран, пока вы в игре
-
- Режим звонка в игре
-
- - Беззвучный
- - Вибрация
- - Нормальный
-
-
- Блокировать полноэкранные уведомления
- Предотвращать появление полноэкранных уведомлений, таких как входящие вызовы, во время игры.
-
- Настроить игру
- Предпочтительный режим
-
- - Стандартный
- - Производительный
- - Экономный
-
-
- Использовать ANGLE (эксперементально)
- Использование рендерера ANGLE вместо собственных драйверов GLES.\nВНИМАНИЕ!! Может ломать игровую графику, использовать с осторожностью!
- ANGLE недоступен в вашей системе
-
- Удалить %1$s из библиотеки
-
-
diff --git a/app/src/main/res/values-sk-rSK/strings.xml b/app/src/main/res/values-sk-rSK/strings.xml
new file mode 100644
index 00000000..c42ad185
--- /dev/null
+++ b/app/src/main/res/values-sk-rSK/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Rýchly štart aplikácií
+ Vybrať aplikácie pre rýchly štart
+ Herný priestor
+ Správa herných nastavení
+
+ Možnosti v hre
+ Blokovať udalosti na celej obrazovke
+ Nezobrazovať udalosti na celej obrazovke, napr. prichádzajúci hovor
+ Nevypínať obrazovku
+ Gesto uzamknutia
+ Zakázať automatický jas
+ Vypnúť gesto prejdenia troma prstami
+ Zakázať ladenie USB
+ Priehľadnosť vrstvy menu
+
+ Režim upozornení
+ Nezobrazovať
+ Zobraziť plávajúce oznámenia
+ Zobraziť reTicker
+ Zobraziť Danmaku
+
+ Režim zvonenia
+ Tichý
+ Vibrácie
+ Normálny
+ Nemeniť
+
+ Knižnica
+ Pridať
+ Výber hry
+ Hľadať
+ Naozaj odstrániť %1$s zo zoznamu hier?
+
+ Nastaviť hru
+ Preferovaný režim
+ Použiť ANGLE (experimentálne)
+ Namiesto natívnych ovládačov GELS sa používa renderer ANGLE.\nUPOZORNENIE!! Môže narušiť grafiku hry, používajte opatrne!
+ ANGLE nie je k dispozícii
+ Odstrániť %1$s z knižnice
+ Nepodporované
+ Štandardný
+ Výkon
+ Batéria
+
+ Hodnota: %s
+ predvolená
+ Predvolená hodnota: %s\nPodržte pre nastavenie
+ Predvolená hodnota je nastavená
+
+ Batéria: %1$d%%
+ Dostupná pamäť: %1$d\/%2$d MB
+
+ Režim
+ FPS info
+ Skryť
+ Plávajúce upozornenia
+ reTicker
+ Len textové notifikácie
+ Zapnuté
+ Zakázané
+ Predvolené
+ Režim hovorov
+ Žiadna akcia
+ Automaticky prijať
+ Automaticky odmietnuť
+ Prijatý hovor od %1$s
+ Odmietnutý hovor od %1$s
+
+ Režim notifikácií Danmaku
+ Počas aktívnej hry zobraziť upozornenia ako danmaku alias odrážky
+ Herný mód spustený
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr-rSP/strings.xml
new file mode 100644
index 00000000..f08ef916
--- /dev/null
+++ b/app/src/main/res/values-sr-rSP/strings.xml
@@ -0,0 +1,87 @@
+
+
+
+ Game Space
+ Manage your gaming setup
+
+ In-game options
+ Block fullscreen event
+ Prevent fullscreen events like incoming calls from appearing
+ Stay awake
+ Lock gesture
+ Disable auto-brightness
+ Disable swipe to screenshot
+ Disable USB debugging
+ Overlay menu opacity level
+
+ Notification mode
+ Do not show
+ Show as Heads Up
+ Show as reTicker
+ Show as Danmaku
+
+ Ringer mode
+ Silent
+ Vibrate
+ Normal
+ Do not change
+
+ Library
+ Add
+ Pick your game
+ Search
+ Are you sure you want to remove %1$s from your game list?
+
+ Configure game
+ Preferred mode
+ Use ANGLE (experimental)
+ Using ANGLE renderer instead of native GLES drivers.\nWARNING!! May breaks game graphics, use with caution!
+ ANGLE is not available on your system
+ Remove %1$s from library
+ Unsupported
+ Standard
+ Performance
+ Battery
+
+ Value: %s
+ by default
+ Default value: %s\nLong tap to set
+ Default value is set
+
+ Battery: %1$d%%
+ Memory available: %1$d\/%2$d MB
+
+ Mode
+ FPS info
+ Hide
+ Heads Up
+ reTicker
+ Danmaku
+ Enabled
+ Disabled
+ Default
+ Call mode
+ No action
+ Auto answer
+ Auto reject
+ Received call from %1$s
+ Rejected call from %1$s
+
+ Danmaku Notification mode
+ Show notification as danmaku aka bullet comments while game is active
+
diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml
new file mode 100644
index 00000000..f08ef916
--- /dev/null
+++ b/app/src/main/res/values-sv-rSE/strings.xml
@@ -0,0 +1,87 @@
+
+
+
+ Game Space
+ Manage your gaming setup
+
+ In-game options
+ Block fullscreen event
+ Prevent fullscreen events like incoming calls from appearing
+ Stay awake
+ Lock gesture
+ Disable auto-brightness
+ Disable swipe to screenshot
+ Disable USB debugging
+ Overlay menu opacity level
+
+ Notification mode
+ Do not show
+ Show as Heads Up
+ Show as reTicker
+ Show as Danmaku
+
+ Ringer mode
+ Silent
+ Vibrate
+ Normal
+ Do not change
+
+ Library
+ Add
+ Pick your game
+ Search
+ Are you sure you want to remove %1$s from your game list?
+
+ Configure game
+ Preferred mode
+ Use ANGLE (experimental)
+ Using ANGLE renderer instead of native GLES drivers.\nWARNING!! May breaks game graphics, use with caution!
+ ANGLE is not available on your system
+ Remove %1$s from library
+ Unsupported
+ Standard
+ Performance
+ Battery
+
+ Value: %s
+ by default
+ Default value: %s\nLong tap to set
+ Default value is set
+
+ Battery: %1$d%%
+ Memory available: %1$d\/%2$d MB
+
+ Mode
+ FPS info
+ Hide
+ Heads Up
+ reTicker
+ Danmaku
+ Enabled
+ Disabled
+ Default
+ Call mode
+ No action
+ Auto answer
+ Auto reject
+ Received call from %1$s
+ Rejected call from %1$s
+
+ Danmaku Notification mode
+ Show notification as danmaku aka bullet comments while game is active
+
diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml
new file mode 100644
index 00000000..94a27836
--- /dev/null
+++ b/app/src/main/res/values-tr-rTR/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Hızlı Başlangıç Uygulamaları
+ Hızlı başlatmak için uygulamaları seçin
+ Oyun Alanı
+ Oyun kurulumunuzu yönetin
+
+ Oyun içi seçenekleri
+ Tam ekran etkinliğini engelle
+ Oyun içindeyken gelen aramalar gibi tam ekran etkinliklerinin görünmesini engelleyin
+ Uyanık kal
+ Hareketi kilitle
+ Otomatik parlaklığı devre dışı bırak
+ Üç parmakla kaydırma hareketini devre dışı bırak
+ USB hata ayıklamasını devre dışı bırak
+ Arayüz menüsü şeffaflığı
+
+ Bildirim modu
+ Gösterme
+ Bildirim penceresi olarak göster
+ ReTicker olarak göster
+ Danmaku olarak göster
+
+ Zil sesi modu
+ Sessiz
+ Titreşim
+ Normal
+ Değiştirme
+
+ Arşiv
+ Ekle
+ Oyununu seç
+ Ara
+ %1$s oyun listenizden kaldırmak istediğinizden emin misiniz?
+
+ Oyunu yapılandır
+ Tercih edilen mod
+ ANGLE kullan (deneysel)
+ Yerel GLES sürücüleri yerine ANGLE oluşturucu kullan.\nUYARI!! Oyun grafiklerini bozabilir, dikkatli kullanın!
+ ANGLE sisteminizde mevcut değil
+ %1$s arşivden kaldır
+ Desteklenmiyor
+ Standart
+ Performans
+ Pil
+
+ Değer: %s
+ varsayılan
+ Varsayılan değer: %s\nAyarlamak için uzun basın
+ Varsayılan değer ayarlandı
+
+ Pil: %1$d%%
+ Kullanılabilir bellek: %1$d\/%2$d MB
+
+ Mod
+ FPS bilgisi
+ Gizle
+ Bildirim pencereleri
+ reTicker
+ Danmaku
+ Etkin
+ Devre dışı
+ Varsayılan
+ Çağrı modu
+ Eylem yok
+ Otomatik cevaplama
+ Otomatik reddet
+ %1$s kullanıcısından gelen arama
+ %1$s kullanıcısından gelen arama
+
+ Danmaku Bildirim modu
+ Oyun aktifken danmaku bullet yorumları olarak bildirim göster
+ Oyun Alanı çalışıyor
+
+ Arama penceresi
+ Aramaları yanıtlamak veya reddetmek için minimal arama arayüzünü göster
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml
new file mode 100644
index 00000000..75b50a18
--- /dev/null
+++ b/app/src/main/res/values-uk-rUA/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Програми швидкого старту
+ Виберіть програми для швидкого запуску
+ Ігровий Простір
+ Керування налаштуваннями гри
+
+ Налаштування гри
+ Блокувати повноекранні сповіщення
+ Запобігти появі повноекранних сповіщень, таких як вхідні дзвінки під час гри
+ Залишати активним
+ Жест блокування
+ Вимкнути автояскравість
+ Вимкнути жест руху трьома пальцями
+ Вимкнути налагодження USB
+ Рівень непрозорості меню ігрового режиму
+
+ Режим сповіщень
+ Не показувати
+ Відображаюти як спливаючі сповіщення
+ Показати як в новому стилі спливаючих сповіщень
+ Показати як Данмаку
+
+ Режим дзвінка
+ Беззвучний
+ Вібрація
+ Звичайний
+ Не змінювати
+
+ Бібліотека
+ Додати
+ Виберіть свою гру
+ Пошук
+ Ви впевнені, що хочете видалити %1$s зі свого списку ігор?
+
+ Налаштувати гру
+ Переважний режим
+ Використовувати ANGLE (експериментально)
+ Використовуючи візуалізатор ANGLE замість нативних драйверів GLES.\nУВАГА!! Може порушувати графіку гри, використовуйте з обережністю!
+ ANGLE недоступний у вашій системі
+ Видалити %1$s з бібліотеки
+ Не підтримується
+ Стандартний
+ Продуктивний
+ Батарея
+
+ Значення: %s
+ за замовчуванням
+ Значення за замовчуванням: %s\nДовге натискання для встановлення
+ Значення за замовчуванням встановлено
+
+ Акумулятор: %1$d%%
+ Доступно пам\'яті: %1$d\/%2$d MB
+
+ Режим
+ Інформація про FPS
+ Зховати
+ Спливаючі сповіщення
+ Новий стиль спливаючих сповіщень
+ Данмаку
+ Увімкнено
+ Вимкнено
+ За замовчанням
+ Режим виклику
+ Немає дій
+ Автовідповідач
+ Відхилити автоматично
+ Отримано дзвінок від %1$s
+ Пропущений дзвінок від %1$s
+
+ Режим сповіщень Danmaku
+ Показувати сповіщення як Danmaku aka bullet коментарями під час гри активними
+ Game Space активний
+
+ Накладання викликів
+ Показувати мінімальне накладення для відповіді/відхилення викликів
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml
new file mode 100644
index 00000000..87dc40fd
--- /dev/null
+++ b/app/src/main/res/values-vi-rVN/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ Mở nhanh ứng dụng
+ Chọn ứng dụng để mở nhanh
+ Không gian trò chơi
+ Quản lý thiết lập trò chơi của bạn
+
+ Tùy chọn trong trò chơi
+ Chặn sự kiện toàn màn hình
+ Ngăn các sự kiện toàn màn hình như cuộc gọi đến xuất hiện khi ở trong trò chơi
+ Không khóa màn hình
+ Khóa cử chỉ
+ Tắt độ sáng tự động
+ Tắt cử chỉ vuốt ba ngón tay
+ Tắt gỡ lỗi USB
+ Độ mờ bảng điều khiển nổi
+
+ Kiểu thông báo
+ Không hiển thị
+ Hiện thông báo nổi
+ Thông báo nổi kiểu mới
+ Thông báo nổi kiểu hiện đại
+
+ Chế độ chuông
+ Im lặng
+ Rung
+ Bình thường
+ Không thay đổi
+
+ Thư viện
+ Thêm
+ Chọn trò chơi của bạn
+ Tìm kiếm
+ Bạn có chắc chắn muốn xóa %1$s khỏi danh sách trò chơi chứ?
+
+ Định cấu hình trò chơi
+ Chế độ ưu tiên
+ Sử dụng ANGLE (thử nghiệm)
+ Sử dụng trình kết xuất ANGLE thay vì trình điều khiển GLES gốc.\nCẢNH BÁO!! Có thể phá vỡ đồ họa trò chơi, hãy sử dụng một cách thận trọng!
+ ANGLE không có sẵn trên hệ thống của bạn
+ Xóa %1$s khỏi thư viện
+ Không hỗ trợ
+ Tiêu chuẩn
+ Hiệu suất cao
+ Tiết kiệm pin
+
+ Giá trị: %s
+ mặc định
+ Giá trị mặc định: %s\nNhấn giữ lâu để thiết lập
+ Đã đặt giá trị mặc định
+
+ Pin: %1$d%%
+ Bộ nhớ có sẵn: %1$d\/%2$d MB
+
+ Chế độ
+ Thông tin FPS
+ Ẩn
+ Cửa sổ nổi
+ Kiểu mới
+ Kiểu hiện đại
+ Bật
+ Tắt
+ Mặc định
+ Chế độ cuộc gọi
+ Không làm gì
+ Tự động trả lời
+ Tự động từ chối
+ Nhận cuộc gọi từ %1$s
+ Từ chối cuộc gọi từ %1$s
+
+ Chế độ thông báo hiện đại
+ Hiển thị thông báo hiện đại hay còn gọi là nhận xét về dấu đầu dòng khi trò chơi đang hoạt động
+ Không gian trò chơi đang chạy
+
+ Lớp phủ cuộc gọi
+ Hiển thị lớp phủ tối giản để trả lời/từ chối cuộc gọi
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index a729293d..a387a2cc 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -1,55 +1,113 @@
-
-
-
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+ 快速启动应用程序
+ 选择要快速启动的应用
游戏空间
管理您的游戏设置
+
+ 游戏中选项
+ 屏蔽全屏事件
+ 防止在游戏中出现来电等全屏事件
+ 保持唤醒
+ 锁定手势
+ 禁用自动调节亮度
+ 禁用三指滑动
+ 禁用 USB 调试
+ 覆盖菜单不透明度级别
+
+ 通知模式
+ 不显示
+ 显示为浮动通知
+ 以 reTicker 形式显示
+ 显示为弹幕通知
+
+ 响铃模式
+ 静音
+ 振动
+ 正常
+ 不更改
+
+ 游戏列表
+ 添加
选择您的游戏
- 禁用自动亮度
- 在游戏中保持亮度稳定
- 禁用悬浮通知
- 在游戏中禁用悬浮通知
- 游戏库
- 确定从你的游戏库中删除 %1$s 吗?
搜索
- 游戏中临时禁用三指截图手势
- 禁用三指截图
- chaldeaprjkt
- 已启用
- 禁用
-
+ 您确定要将 %1$s 从您的游戏列表中移除吗?
+
+ 配置游戏
+ 首选模式
+ 使用 ANGLE 渲染器 (实验性)
+ 使用 ANGLE 渲染器而不是本机的 GLES 驱动器。\n警告!! 可能会破坏游戏图形, 请谨慎使用!
+ ANGLE 渲染器在当前系统中不可用
+ 从游戏列表中移除 %1$s
+ 不支持
+ 标准
+ 性能
+ 省电
+
+ 值: %s
+ 默认
+ 默认值: %s\n长按设置
+ 恢复默认值
+
+ 电量: %1$d%%
+ 内存空闲: %1$d\/%2$d MB
+
游戏模式
-
- - 无
- - 均衡
- - 性能
- - 省电
+ FPS 信息
+ 隐藏
+ 浮动通知
+ reTicker
+ 弹幕
+ 已启用
+ 已禁用
+ 默认
+ 通话模式
+ 无操作
+ 自动接听
+ 自动挂断
+ 收到了来自 %1$s 的来电
+ 拒绝了来自 %1$s 的来电
+
+ 弹幕通知模式
+ 游戏中以弹幕的形式显示通知
+ 游戏空间正在运行
+
+ 电话叠加层
+ 显示最小呼叫叠加层以接听/拒接电话
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
- 警告
- 帧率信息
- 永不息屏
- 在游戏中保持亮屏
-
- 游戏内铃声
-
- - 静音
- - 振动
- - 默认
+
+ - balanced
+ - performance
+ - powersave
-
- 阻止全屏事件
- 防止游戏中出现诸如来电之类的全屏事件
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
new file mode 100644
index 00000000..ced75483
--- /dev/null
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -0,0 +1,113 @@
+
+
+
+ 快速啟動應用程式
+ 選擇要快速啟動的應用程式
+ 遊戲空間
+ 管理您的遊戲設定
+
+ 遊戲中選項
+ 封鎖全螢幕活動
+ 防止如電話等的應用程式彈出全螢幕畫面
+ 螢幕保持開啟
+ 鎖定手勢
+ 停用自動亮度
+ 停用三指滑動手勢
+ 停用 USB 偵錯
+ 不透明度
+
+ 通知模式
+ 不顯示
+ 彈出式通知
+ reTicker
+ 彈幕式通知
+
+ 鈴聲模式
+ 靜音
+ 震動
+ 正常
+ 不變更
+
+ 遊戲庫
+ 新增
+ 選擇遊戲
+ 搜尋
+ 您確定要將 %1$s 從遊戲庫移除嗎?
+
+ 遊戲選項
+ 偏好模式
+ 使用 ANGLE (實驗性功能)
+ 使用 ANGLE 渲染畫面而非原生的 GLES 驅動。\n警告!遊戲畫面可能出現破圖等現象,請謹慎使用。
+ 您的系統不支援 ANGLE
+ 從遊戲庫中移除 %1$s
+ 不支援
+ 一般
+ 高效能
+ 省電
+
+ 數值: %s
+ 預設
+ 預設值:%s\n長按以設定
+ 已設定為預設值
+
+ 電量: %1$d%%
+ 可用記憶體:%1$d\/%2$d MB
+
+ 模式
+ 幀數
+ 隱藏
+ 彈出通知
+ reTicker
+ 彈幕式通知
+ 已啟用
+ 已停用
+ 預設
+ 通話模式
+ 不採取動作
+ 自動接聽
+ 自動拒接
+ 接聽 %1$s 的來電
+ 錯過 %1$s 的來電
+
+ 彈幕通知模式
+ 遊戲中以彈幕形式顯示通知。
+ 游戲空間正在運行
+
+ 電話疊加層
+ 顯示最少的通話疊加層以接聽/拒接電話
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+ - balanced
+ - performance
+ - powersave
+
+
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 55ae50f6..7cb0011d 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -15,7 +15,23 @@
-->
+
+
+ - @string/game_mode_unsupported
+ - @string/game_mode_standard
+ - @string/game_mode_performance
+ - @string/game_mode_battery
+
+
+
+ - @string/ringer_mode_no_change
+ - @string/ringer_mode_silent
+ - @string/ringer_mode_vibrate
+ - @string/ringer_mode_normal
+
+
+ - 3
- 0
- 1
- 2
@@ -26,4 +42,36 @@
- 2
- 3
+
+
+ - @string/game_mode_standard
+ - @string/game_mode_performance
+ - @string/game_mode_battery
+
+
+
+ - @string/notification_mode_hide
+ - @string/notification_mode_headsup
+ - @string/notification_mode_reticker
+ - @string/notification_mode_danmaku
+
+
+
+ - 0
+ - 1
+ - 2
+ - 3
+
+
+
+ - @string/in_game_calls_no_action
+ - @string/in_game_calls_auto_answer
+ - @string/in_game_calls_auto_reject
+
+
+
+ - 0
+ - 1
+ - 2
+
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100644
index 00000000..a3f1bdd2
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index fa9957ae..91362bd4 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -10,10 +10,11 @@
@android:color/system_neutral1_900
@android:color/system_neutral1_900
- #000000
- #A0000000
- @android:color/system_accent1_700
- #000000
- @android:color/system_accent1_400
- #c0c0c0
+ @android:color/system_neutral1_50
+ @android:color/system_neutral1_50
+ @android:color/system_accent1_600
+ @android:color/system_accent1_600
+ @android:color/system_accent2_500
+ @android:color/system_neutral1_0
+ @android:color/system_neutral1_1000
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index a7be8e51..acb95e7a 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -17,4 +17,7 @@
36dp
+
+ 48dp
+ 36dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e94b2a6a..0f33be4c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,70 +1,129 @@
-
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
-
+ Quick Start Apps
+ Select apps to launch quickly
Game Space
Manage your gaming setup
- Pick your game
+
+
+ In-game options
+ Block fullscreen event
+ Prevent fullscreen events like incoming calls from appearing
+ Stay awake
+ Lock gesture
Disable auto-brightness
- Keep brightness settled while in-game
- Disable heads-up
- Disable Notification heads-up while in-game
- Library
- Are you sure you want to remove %1$s from your library ?
- Search
- Temporary disable three-fingers-swipe screenshot gesture while in-game
- Disable swipe to screenshot
- chaldeaprjkt
- enabled
- disabled
-
- Mode
-
- - Unsupported
- - Standard
- - Performance
- - Battery
-
- Heads-up
- FPS Info
- Stay Awake
- Keep screen awake while in the game
+ Disable three fingers swipe gesture
+ Disable USB debugging
+ Overlay menu opacity level
- In-game ringer mode
-
- - Silent
- - Vibrate
- - Normal
-
+
+ Notification mode
+ Do not show
+ Show as Heads Up
+ Show as reTicker
+ Show as Danmaku
- Block fullscreen event
- Prevent fullscreen events like incoming calls from appearing while in-game
+
+ Ringer mode
+ Silent
+ Vibrate
+ Normal
+ Do not change
- Configure Game
- Preferred Mode
-
- - Standard
- - Performance
- - Battery
-
+
+ Library
+ Add
+ Pick your game
+ Search
+ Are you sure you want to remove %1$s from your game list?
+
+ Configure game
+ Preferred mode
Use ANGLE (experimental)
Using ANGLE renderer instead of native GLES drivers.\nWARNING!! May breaks game graphics, use with caution!
ANGLE is not available on your system
-
Remove %1$s from library
+ Unsupported
+ Standard
+ Performance
+ Battery
+
+
+ Value: %s
+ by default
+ Default value: %s\nLong tap to set
+ Default value is set
+
+
+ Battery: %1$d%%
+ Memory available: %1$d\/%2$d MB
+
+
+ Mode
+ FPS info
+ Hide
+ Heads Up
+ reTicker
+ Danmaku
+ Enabled
+ Disabled
+ Default
+
+ Call mode
+ No action
+ Auto answer
+ Auto reject
+ Received call from %1$s
+ Rejected call from %1$s
+
+
+ Danmaku Notification mode
+ Show notification as danmaku aka bullet comments while game is active
+
+ Game Space is running
+
+
+ Call overlay
+ Show minimal call overlay to answer/reject calls
+
+ Launch Optimization
+ Launch Boost
+ Optimize CPU and memory for faster game launch
+ Smart Memory Management
+ Automatically clear background apps when launching games
+ Loading Priority
+ Set resource priority during game launch
+ Cache Management
+ Optimize game cache for faster loading times
+
+
+ - Balanced (Recommended)
+ - Maximum Performance
+ - Power Saving
+
+
+
+ - balanced
+ - performance
+ - powersave
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index cd4800eb..11a3585e 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -16,9 +16,9 @@
-
+
-
diff --git a/app/src/main/res/xml/per_app_preferences.xml b/app/src/main/res/xml/per_app_preferences.xml
index 45ac1caa..6be5192b 100644
--- a/app/src/main/res/xml/per_app_preferences.xml
+++ b/app/src/main/res/xml/per_app_preferences.xml
@@ -1,25 +1,28 @@
-
-
+
+
-
+ android:layout="@layout/per_app_header"
+ app:allowDividerAbove="false"
+ app:allowDividerBelow="false" />
-
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
-
-
-
+
+
+
+
-
-
+ android:key="gamespace_adb_disabled"
+ android:title="@string/adb_disabled_title" />
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
index 5a48e391..25bdc04f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,10 +1,21 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id 'com.android.application' version '7.1.0-beta05' apply false
- id 'com.android.library' version '7.1.0-beta05' apply false
- id 'org.jetbrains.kotlin.android' version '1.6.0' apply false
+ id 'com.android.application' version '7.4.2' apply false
+ id 'com.android.library' version '7.4.2' apply false
+ id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
}
-task clean(type: Delete) {
+tasks.register('clean') {
delete rootProject.buildDir
-}
\ No newline at end of file
+}
+
+allprojects {
+ ext.frameworkJar = "${rootDir}/prebuilts/framework.jar"
+
+ gradle.projectsEvaluated {
+ tasks.withType(JavaCompile).tap {
+ configureEach {
+ options.compilerArgs.add("-Xbootclasspath/p:$frameworkJar")
+ }
+ }
+ }
+}
diff --git a/crowdin.yml b/crowdin.yml
new file mode 100644
index 00000000..7fb1274d
--- /dev/null
+++ b/crowdin.yml
@@ -0,0 +1,3 @@
+files:
+ - source: /app/src/main/res/values/strings.xml
+ translation: /app/src/main/res/values-%android_code%/%original_file_name%
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f0637684..e8a522aa 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Mon Nov 22 21:23:34 WIB 2021
distributionBase=GRADLE_USER_HOME
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
diff --git a/settings.gradle b/settings.gradle
index 2b88ee7b..8a6ce76e 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -14,4 +14,4 @@ dependencyResolutionManagement {
}
rootProject.name = "GameSpace"
include ':app'
-include ':SettingsLibParts'
+include ':SettingsLib'