Use the fragment backstack properly, and use fragment animations.
Make the MenuFragment added and removed by fragment transactions only, instead of being initially present in the XML. This fixes a glitch where it doesn't animate correctly the first time it's used.
This commit is contained in:
parent
c4d7814afa
commit
94ed30b055
|
@ -14,6 +14,7 @@ import android.preference.PreferenceManager;
|
||||||
import android.support.annotation.IntDef;
|
import android.support.annotation.IntDef;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.FragmentActivity;
|
import android.support.v4.app.FragmentActivity;
|
||||||
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.view.InputDevice;
|
import android.view.InputDevice;
|
||||||
|
@ -24,7 +25,6 @@ import android.view.MenuItem;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
@ -42,7 +42,6 @@ import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
||||||
import org.dolphinemu.dolphinemu.utils.Animations;
|
import org.dolphinemu.dolphinemu.utils.Animations;
|
||||||
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
|
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
|
||||||
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
|
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
|
||||||
import org.dolphinemu.dolphinemu.utils.Log;
|
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -51,13 +50,12 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||||
|
|
||||||
public final class EmulationActivity extends AppCompatActivity
|
public final class EmulationActivity extends AppCompatActivity
|
||||||
{
|
{
|
||||||
private static final String FRAGMENT_SUBMENU_TAG = "submenu";
|
private static final String BACKSTACK_NAME_MENU = "menu";
|
||||||
|
private static final String BACKSTACK_NAME_SUBMENU = "submenu";
|
||||||
private View mDecorView;
|
private View mDecorView;
|
||||||
private ImageView mImageView;
|
private ImageView mImageView;
|
||||||
private EmulationFragment mEmulationFragment;
|
private EmulationFragment mEmulationFragment;
|
||||||
|
|
||||||
private LinearLayout mMenuLayout;
|
|
||||||
|
|
||||||
private SharedPreferences mPreferences;
|
private SharedPreferences mPreferences;
|
||||||
|
|
||||||
// So that MainActivity knows which view to invalidate before the return animation.
|
// So that MainActivity knows which view to invalidate before the return animation.
|
||||||
|
@ -66,7 +64,6 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
private boolean mDeviceHasTouchScreen;
|
private boolean mDeviceHasTouchScreen;
|
||||||
private boolean mSystemUiVisible;
|
private boolean mSystemUiVisible;
|
||||||
private boolean mMenuVisible;
|
private boolean mMenuVisible;
|
||||||
private boolean mSubMenuVisible = false;
|
|
||||||
|
|
||||||
private static boolean mIsGameCubeGame;
|
private static boolean mIsGameCubeGame;
|
||||||
|
|
||||||
|
@ -221,7 +218,6 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
setContentView(R.layout.activity_emulation);
|
setContentView(R.layout.activity_emulation);
|
||||||
|
|
||||||
mImageView = (ImageView) findViewById(R.id.image_screenshot);
|
mImageView = (ImageView) findViewById(R.id.image_screenshot);
|
||||||
mMenuLayout = (LinearLayout) findViewById(R.id.layout_ingame_menu);
|
|
||||||
mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
|
mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
|
||||||
.findFragmentById(R.id.fragment_emulation);
|
.findFragmentById(R.id.fragment_emulation);
|
||||||
|
|
||||||
|
@ -280,16 +276,6 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
{
|
{
|
||||||
setTitle(mSelectedTitle);
|
setTitle(mSelectedTitle);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
MenuFragment menuFragment = (MenuFragment) getSupportFragmentManager()
|
|
||||||
.findFragmentById(R.id.fragment_menu);
|
|
||||||
|
|
||||||
if (menuFragment != null)
|
|
||||||
{
|
|
||||||
menuFragment.setTitleText(mSelectedTitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
@ -333,11 +319,9 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
{
|
{
|
||||||
if (!mDeviceHasTouchScreen)
|
if (!mDeviceHasTouchScreen)
|
||||||
{
|
{
|
||||||
if (mSubMenuVisible)
|
boolean popResult = getSupportFragmentManager().popBackStackImmediate(
|
||||||
{
|
BACKSTACK_NAME_SUBMENU, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||||
removeSubMenu();
|
if (!popResult)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
toggleMenu();
|
toggleMenu();
|
||||||
}
|
}
|
||||||
|
@ -347,31 +331,28 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
mEmulationFragment.stopEmulation();
|
mEmulationFragment.stopEmulation();
|
||||||
exitWithAnimation();
|
exitWithAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toggleMenu()
|
private void toggleMenu()
|
||||||
{
|
{
|
||||||
if (mMenuVisible)
|
boolean result = getSupportFragmentManager().popBackStackImmediate(
|
||||||
{
|
BACKSTACK_NAME_MENU, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||||
mMenuVisible = false;
|
mMenuVisible = false;
|
||||||
|
|
||||||
Animations.fadeViewOutToLeft(mMenuLayout)
|
if (!result) {
|
||||||
.withEndAction(new Runnable()
|
// Removing the menu failed, so that means it wasn't visible. Add it.
|
||||||
{
|
Fragment fragment = MenuFragment.newInstance(mSelectedTitle);
|
||||||
@Override
|
getSupportFragmentManager().beginTransaction()
|
||||||
public void run()
|
.setCustomAnimations(
|
||||||
{
|
R.animator.menu_slide_in_from_left,
|
||||||
if (mMenuVisible)
|
R.animator.menu_slide_out_to_left,
|
||||||
{
|
R.animator.menu_slide_in_from_left,
|
||||||
mMenuLayout.setVisibility(View.GONE);
|
R.animator.menu_slide_out_to_left)
|
||||||
}
|
.add(R.id.frame_menu, fragment)
|
||||||
}
|
.addToBackStack(BACKSTACK_NAME_MENU)
|
||||||
});
|
.commit();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mMenuVisible = true;
|
mMenuVisible = true;
|
||||||
Animations.fadeViewInFromLeft(mMenuLayout);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,14 +477,14 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
case MENU_ACTION_SAVE_ROOT:
|
case MENU_ACTION_SAVE_ROOT:
|
||||||
if (!mDeviceHasTouchScreen)
|
if (!mDeviceHasTouchScreen)
|
||||||
{
|
{
|
||||||
showMenu(SaveLoadStateFragment.SaveOrLoad.SAVE);
|
showSubMenu(SaveLoadStateFragment.SaveOrLoad.SAVE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case MENU_ACTION_LOAD_ROOT:
|
case MENU_ACTION_LOAD_ROOT:
|
||||||
if (!mDeviceHasTouchScreen)
|
if (!mDeviceHasTouchScreen)
|
||||||
{
|
{
|
||||||
showMenu(SaveLoadStateFragment.SaveOrLoad.LOAD);
|
showSubMenu(SaveLoadStateFragment.SaveOrLoad.LOAD);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -817,44 +798,22 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
hideSystemUiAfterDelay();
|
hideSystemUiAfterDelay();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad)
|
private void showSubMenu(SaveLoadStateFragment.SaveOrLoad saveOrLoad)
|
||||||
{
|
{
|
||||||
|
// Get rid of any visible submenu
|
||||||
|
getSupportFragmentManager().popBackStack(
|
||||||
|
BACKSTACK_NAME_SUBMENU, FragmentManager.POP_BACK_STACK_INCLUSIVE);
|
||||||
|
|
||||||
Fragment fragment = SaveLoadStateFragment.newInstance(saveOrLoad);
|
Fragment fragment = SaveLoadStateFragment.newInstance(saveOrLoad);
|
||||||
getSupportFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
.setCustomAnimations(R.animator.menu_slide_in, R.animator.menu_slide_out)
|
.setCustomAnimations(
|
||||||
.replace(R.id.frame_submenu, fragment, FRAGMENT_SUBMENU_TAG)
|
R.animator.menu_slide_in_from_right,
|
||||||
|
R.animator.menu_slide_out_to_right,
|
||||||
|
R.animator.menu_slide_in_from_right,
|
||||||
|
R.animator.menu_slide_out_to_right)
|
||||||
|
.replace(R.id.frame_submenu, fragment)
|
||||||
|
.addToBackStack(BACKSTACK_NAME_SUBMENU)
|
||||||
.commit();
|
.commit();
|
||||||
mSubMenuVisible = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void removeSubMenu()
|
|
||||||
{
|
|
||||||
final Fragment fragment = getSupportFragmentManager().findFragmentByTag(FRAGMENT_SUBMENU_TAG);
|
|
||||||
|
|
||||||
if (fragment != null)
|
|
||||||
{
|
|
||||||
// When removing a fragment without replacement, its animation must be done
|
|
||||||
// manually beforehand.
|
|
||||||
Animations.fadeViewOutToRight(fragment.getView())
|
|
||||||
.withEndAction(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (mMenuVisible)
|
|
||||||
{
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
|
||||||
.remove(fragment)
|
|
||||||
.commit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.error("[EmulationActivity] Fragment not found, can't remove.");
|
|
||||||
}
|
|
||||||
mSubMenuVisible = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getSelectedTitle()
|
public String getSelectedTitle()
|
||||||
|
|
|
@ -16,7 +16,7 @@ import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
|
|
||||||
public final class MenuFragment extends Fragment implements View.OnClickListener
|
public final class MenuFragment extends Fragment implements View.OnClickListener
|
||||||
{
|
{
|
||||||
private TextView mTitleText;
|
private static final String KEY_TITLE = "title";
|
||||||
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
|
private static SparseIntArray buttonsActionsMap = new SparseIntArray();
|
||||||
static {
|
static {
|
||||||
buttonsActionsMap.append(R.id.menu_take_screenshot, EmulationActivity.MENU_ACTION_TAKE_SCREENSHOT);
|
buttonsActionsMap.append(R.id.menu_take_screenshot, EmulationActivity.MENU_ACTION_TAKE_SCREENSHOT);
|
||||||
|
@ -28,6 +28,17 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
|
||||||
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
|
buttonsActionsMap.append(R.id.menu_exit, EmulationActivity.MENU_ACTION_EXIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static MenuFragment newInstance(String title)
|
||||||
|
{
|
||||||
|
MenuFragment fragment = new MenuFragment();
|
||||||
|
|
||||||
|
Bundle arguments = new Bundle();
|
||||||
|
arguments.putSerializable(KEY_TITLE, title);
|
||||||
|
fragment.setArguments(arguments);
|
||||||
|
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
|
||||||
|
@ -42,7 +53,12 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
|
||||||
button.setOnClickListener(this);
|
button.setOnClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
mTitleText = (TextView) rootView.findViewById(R.id.text_game_title);
|
TextView titleText = rootView.findViewById(R.id.text_game_title);
|
||||||
|
String title = getArguments().getString(KEY_TITLE);
|
||||||
|
if (title != null)
|
||||||
|
{
|
||||||
|
titleText.setText(title);
|
||||||
|
}
|
||||||
|
|
||||||
return rootView;
|
return rootView;
|
||||||
}
|
}
|
||||||
|
@ -57,9 +73,4 @@ public final class MenuFragment extends Fragment implements View.OnClickListener
|
||||||
((EmulationActivity) getActivity()).handleMenuAction(action);
|
((EmulationActivity) getActivity()).handleMenuAction(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTitleText(String title)
|
|
||||||
{
|
|
||||||
mTitleText.setText(title);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,55 +2,13 @@ package org.dolphinemu.dolphinemu.utils;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewPropertyAnimator;
|
import android.view.ViewPropertyAnimator;
|
||||||
import android.view.animation.AccelerateInterpolator;
|
|
||||||
import android.view.animation.DecelerateInterpolator;
|
|
||||||
import android.view.animation.Interpolator;
|
|
||||||
|
|
||||||
public final class Animations
|
public final class Animations
|
||||||
{
|
{
|
||||||
private static final Interpolator DECELERATOR = new DecelerateInterpolator();
|
|
||||||
private static final Interpolator ACCELERATOR = new AccelerateInterpolator();
|
|
||||||
|
|
||||||
private Animations()
|
private Animations()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ViewPropertyAnimator fadeViewOutToRight(View view)
|
|
||||||
{
|
|
||||||
return view.animate()
|
|
||||||
.withLayer()
|
|
||||||
.setDuration(200)
|
|
||||||
.setInterpolator(ACCELERATOR)
|
|
||||||
.alpha(0.0f)
|
|
||||||
.translationX(view.getWidth());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ViewPropertyAnimator fadeViewOutToLeft(View view)
|
|
||||||
{
|
|
||||||
return view.animate()
|
|
||||||
.withLayer()
|
|
||||||
.setDuration(200)
|
|
||||||
.setInterpolator(ACCELERATOR)
|
|
||||||
.alpha(0.0f)
|
|
||||||
.translationX(-view.getWidth());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ViewPropertyAnimator fadeViewInFromLeft(View view)
|
|
||||||
{
|
|
||||||
|
|
||||||
view.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
view.setTranslationX(-view.getWidth());
|
|
||||||
view.setAlpha(0.0f);
|
|
||||||
|
|
||||||
return view.animate()
|
|
||||||
.withLayer()
|
|
||||||
.setDuration(300)
|
|
||||||
.setInterpolator(DECELERATOR)
|
|
||||||
.alpha(1.0f)
|
|
||||||
.translationX(0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ViewPropertyAnimator fadeViewIn(View view)
|
public static ViewPropertyAnimator fadeViewIn(View view)
|
||||||
{
|
{
|
||||||
view.setVisibility(View.VISIBLE);
|
view.setVisibility(View.VISIBLE);
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<objectAnimator
|
||||||
|
android:propertyName="translationX"
|
||||||
|
android:valueType="floatType"
|
||||||
|
android:valueFrom="-1280dp"
|
||||||
|
android:valueTo="0"
|
||||||
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
|
android:duration="300"/>
|
||||||
|
|
||||||
|
<objectAnimator
|
||||||
|
android:propertyName="alpha"
|
||||||
|
android:valueType="floatType"
|
||||||
|
android:valueFrom="0"
|
||||||
|
android:valueTo="1"
|
||||||
|
android:interpolator="@android:interpolator/accelerate_quad"
|
||||||
|
android:duration="300"/>
|
||||||
|
|
||||||
|
</set>
|
|
@ -4,7 +4,7 @@
|
||||||
<objectAnimator
|
<objectAnimator
|
||||||
android:propertyName="translationX"
|
android:propertyName="translationX"
|
||||||
android:valueType="floatType"
|
android:valueType="floatType"
|
||||||
android:valueFrom="1280"
|
android:valueFrom="1280dp"
|
||||||
android:valueTo="0"
|
android:valueTo="0"
|
||||||
android:interpolator="@android:interpolator/decelerate_quad"
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
android:duration="300"/>
|
android:duration="300"/>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<!-- This animation is used ONLY when a submenu is replaced. -->
|
||||||
|
<objectAnimator
|
||||||
|
android:propertyName="translationX"
|
||||||
|
android:valueType="floatType"
|
||||||
|
android:valueFrom="0"
|
||||||
|
android:valueTo="-1280dp"
|
||||||
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
|
android:duration="200"/>
|
||||||
|
|
||||||
|
<objectAnimator
|
||||||
|
android:propertyName="alpha"
|
||||||
|
android:valueType="floatType"
|
||||||
|
android:valueFrom="1"
|
||||||
|
android:valueTo="0"
|
||||||
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
|
android:duration="200"/>
|
||||||
|
|
||||||
|
</set>
|
|
@ -6,9 +6,9 @@
|
||||||
android:propertyName="translationX"
|
android:propertyName="translationX"
|
||||||
android:valueType="floatType"
|
android:valueType="floatType"
|
||||||
android:valueFrom="0"
|
android:valueFrom="0"
|
||||||
android:valueTo="1280"
|
android:valueTo="1280dp"
|
||||||
android:interpolator="@android:interpolator/decelerate_quad"
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
android:duration="300"/>
|
android:duration="200"/>
|
||||||
|
|
||||||
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:propertyName="alpha"
|
android:propertyName="alpha"
|
||||||
|
@ -16,6 +16,6 @@
|
||||||
android:valueFrom="1"
|
android:valueFrom="1"
|
||||||
android:valueTo="0"
|
android:valueTo="0"
|
||||||
android:interpolator="@android:interpolator/decelerate_quad"
|
android:interpolator="@android:interpolator/decelerate_quad"
|
||||||
android:duration="300"/>
|
android:duration="200"/>
|
||||||
|
|
||||||
</set>
|
</set>
|
|
@ -21,28 +21,24 @@
|
||||||
android:id="@+id/image_screenshot"
|
android:id="@+id/image_screenshot"
|
||||||
android:transitionName="image_game_screenshot"/>
|
android:transitionName="image_game_screenshot"/>
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/layout_ingame_menu"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal">
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible"
|
|
||||||
android:baselineAligned="false">
|
|
||||||
|
|
||||||
<fragment
|
<FrameLayout
|
||||||
android:id="@+id/fragment_menu"
|
android:id="@+id/frame_menu"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="1"
|
android:layout_weight=".25"
|
||||||
android:name="org.dolphinemu.dolphinemu.fragments.MenuFragment"
|
|
||||||
tools:layout="@layout/fragment_ingame_menu"/>
|
tools:layout="@layout/fragment_ingame_menu"/>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/frame_submenu"
|
android:id="@+id/frame_submenu"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_weight="3"/>
|
android:layout_weight=".75"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue