Commit 6df7df3b authored by Haiyang Pan's avatar Haiyang Pan Committed by Commit Bot

Revert "Download later: Implements lots of things in download later dialog."

This reverts commit 5a04dad7.

Reason for revert: Tests crash consistently since the builds
https://ci.chromium.org/p/chromium/builders/ci/android-pie-x86-rel/1294
https://ci.chromium.org/p/chromium/builders/ci/android-arm64-proguard-rel/2083
And flakily since https://ci.chromium.org/p/chromium/builders/ci/android-pie-arm64-rel/5696

Original change's description:
> Download later: Implements lots of things in download later dialog.
> 
> This CL does the following:
> 
> 1. Implements the checkbox.
> 2. Implements the edit location text, which triggers location dialog.
> 3. Make download later dialog owns a date time picker, so other callers
> can share the glue code between later dialog and date time picker.
> 4. Lots of tests added, lots of code refactored.
> 
> TBR=dtrainor@chromium.org
> 
> Bug: 1099989,1078454
> Change-Id: I3dd53c0a0694c91789398382c6deb11fbfe8006d
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2268467
> Reviewed-by: Shakti Sahu <shaktisahu@chromium.org>
> Reviewed-by: Hesen Zhang <hesen@chromium.org>
> Commit-Queue: Xing Liu <xingliu@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#784260}

TBR=dtrainor@chromium.org,qinmin@chromium.org,shaktisahu@chromium.org,xingliu@chromium.org,hesen@chromium.org

Change-Id: Idd5217d490c209c38a2fc1174d771daa9c877c62
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1099989, 1078454
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2278124Reviewed-by: default avatarHaiyang Pan <hypan@google.com>
Commit-Queue: Haiyang Pan <hypan@google.com>
Cr-Commit-Position: refs/heads/master@{#784447}
parent 8d2ef827
......@@ -58,7 +58,8 @@ public class DownloadDateTimePickerDialogTest {
.with(DownloadDateTimePickerDialogProperties.STATE, State.DATE)
.with(DownloadDateTimePickerDialogProperties.INITIAL_TIME, now)
.with(DownloadDateTimePickerDialogProperties.MIN_TIME, now)
.with(DownloadDateTimePickerDialogProperties.MAX_TIME, now + 100000000)
.with(DownloadDateTimePickerDialogProperties.MAX_TIME,
now + DownloadDateTimePickerDialogCoordinator.MAX_TIME)
.build();
mDialog = new DownloadDateTimePickerDialogCoordinator();
Assert.assertNotNull(mController);
......
......@@ -4,13 +4,8 @@
package org.chromium.chrome.browser.download.dialogs;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import androidx.test.filters.MediumTest;
......@@ -26,11 +21,9 @@ import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.browser.download.DownloadLaterPromptStatus;
import org.chromium.chrome.browser.download.R;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.components.browser_ui.widget.RadioButtonWithDescription;
import org.chromium.components.prefs.PrefService;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
......@@ -44,8 +37,6 @@ import org.chromium.ui.modelutil.PropertyModel;
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class DownloadLaterDialogTest {
private static final long INVALID_START_TIME = -1;
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
......@@ -55,12 +46,6 @@ public class DownloadLaterDialogTest {
@Mock
private DownloadLaterDialogController mController;
@Mock
DownloadDateTimePickerDialogCoordinator mDateTimePicker;
@Mock
PrefService mPrefService;
private ModalDialogManager getModalDialogManager() {
return mActivityTestRule.getActivity().getModalDialogManager();
}
......@@ -73,12 +58,8 @@ public class DownloadLaterDialogTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mPrefService.getInteger(Pref.DOWNLOAD_LATER_PROMPT_STATUS))
.thenReturn(DownloadLaterPromptStatus.SHOW_INITIAL);
mActivityTestRule.startMainActivityOnBlankPage();
TestThreadUtils.runOnUiThreadBlocking(() -> {
mDialogCoordinator = new DownloadLaterDialogCoordinator(mDateTimePicker);
mModel = new PropertyModel.Builder(DownloadLaterDialogProperties.ALL_KEYS)
.with(DownloadLaterDialogProperties.CONTROLLER, mDialogCoordinator)
.with(DownloadLaterDialogProperties.DOWNLOAD_TIME_INITIAL_SELECTION,
......@@ -86,6 +67,7 @@ public class DownloadLaterDialogTest {
.with(DownloadLaterDialogProperties.DONT_SHOW_AGAIN_SELECTION,
DownloadLaterPromptStatus.SHOW_INITIAL)
.build();
mDialogCoordinator = new DownloadLaterDialogCoordinator();
Assert.assertNotNull(mController);
mDialogCoordinator.initialize(mController);
});
......@@ -93,7 +75,7 @@ public class DownloadLaterDialogTest {
private void showDialog() {
mDialogCoordinator.showDialog(
mActivityTestRule.getActivity(), getModalDialogManager(), mPrefService, mModel);
mActivityTestRule.getActivity(), getModalDialogManager(), mModel);
}
private void clickPositiveButton() {
......@@ -152,25 +134,8 @@ public class DownloadLaterDialogTest {
getDownloadLaterDialogView().onCheckedChanged(null, -1);
clickPositiveButton();
verify(mController)
.onDownloadLaterDialogComplete(
eq(DownloadLaterDialogChoice.DOWNLOAD_NOW), eq(INVALID_START_TIME));
});
}
@Test
@MediumTest
public void testSelectDownloadLater() {
TestThreadUtils.runOnUiThreadBlocking(() -> {
showDialog();
RadioButtonWithDescription downloadLaterButton =
getDownloadLaterDialogView().findViewById(R.id.choose_date_time);
Assert.assertNotNull(downloadLaterButton);
downloadLaterButton.setChecked(true);
getDownloadLaterDialogView().onCheckedChanged(null, -1);
clickPositiveButton();
verify(mController, times(0)).onDownloadLaterDialogComplete(anyInt(), anyLong());
verify(mDateTimePicker).showDialog(any(), any(), any());
.onDownloadLaterDialogComplete(eq(DownloadLaterDialogChoice.DOWNLOAD_NOW),
eq(DownloadLaterPromptStatus.DONT_SHOW));
});
}
}
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.download.dialogs;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
......@@ -17,6 +18,8 @@ import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import java.util.concurrent.TimeUnit;
/**
* The coordinator for download date time picker. The user can pick an exact time to start the
* download later. The dialog has two stage:
......@@ -24,6 +27,8 @@ import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
* 2. A clock to let the user to pick a time.
*/
public class DownloadDateTimePickerDialogCoordinator implements ModalDialogProperties.Controller {
/** The maximum time that the user can select in the dialog.*/
public static final long MAX_TIME = TimeUnit.DAYS.toMillis(7); /* 7 days */
/**
* The controller that receives events from the date time picker.
*/
......@@ -59,25 +64,24 @@ public class DownloadDateTimePickerDialogCoordinator implements ModalDialogPrope
/**
* Shows the date time picker.
* @param context The {@link Context} for the date time picker.
* @param windowAndroid The window android handle that provides contexts.
* @param model The model that defines the application data used to update the UI view.
*/
public void showDialog(
Context context, ModalDialogManager modalDialogManager, PropertyModel model) {
if (context == null || modalDialogManager == null) {
Activity activity, ModalDialogManager modalDialogManager, PropertyModel model) {
if (activity == null || modalDialogManager == null) {
onDismiss(null, DialogDismissalCause.ACTIVITY_DESTROYED);
return;
}
mModalDialogManager = modalDialogManager;
mModel = model;
mView = (DownloadDateTimePickerView) LayoutInflater.from(context).inflate(
mView = (DownloadDateTimePickerView) LayoutInflater.from(activity).inflate(
R.layout.download_later_date_time_picker_dialog, null);
mProcessor = PropertyModelChangeProcessor.create(mModel, mView,
DownloadDateTimePickerView.Binder::bind, true /*performInitialBind*/);
mModalDialogManager.showDialog(
getModalDialogModel(context), ModalDialogManager.ModalDialogType.APP);
getModalDialogModel(activity), ModalDialogManager.ModalDialogType.APP);
}
/**
......
......@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.download.dialogs;
import org.chromium.chrome.browser.download.DownloadLaterPromptStatus;
/**
* Receives events from download later dialog.
*/
......@@ -11,10 +13,10 @@ public interface DownloadLaterDialogController {
/**
* Called when the selection changed in the download later dialog.
* @param choice The selection of the download time in the download later dialog.
* @param startTime The start time of the download, selected int the date time picker, or -1
* if the user didn't select the time.
* @param promptStatus The prompt status about the "don't show again" checkbox.
*/
void onDownloadLaterDialogComplete(@DownloadLaterDialogChoice int choice, long startTime);
void onDownloadLaterDialogComplete(
@DownloadLaterDialogChoice int choice, @DownloadLaterPromptStatus int promptStatus);
/**
* Called when the user cancels or dismisses the download location dialog.
......
......@@ -4,15 +4,14 @@
package org.chromium.chrome.browser.download.dialogs;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import androidx.annotation.NonNull;
import org.chromium.chrome.browser.download.DownloadLaterPromptStatus;
import org.chromium.chrome.browser.download.R;
import org.chromium.chrome.browser.download.dialogs.DownloadDateTimePickerDialogProperties.State;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.components.prefs.PrefService;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogProperties;
......@@ -24,34 +23,15 @@ import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
* Coordinator to construct the download later dialog.
*/
public class DownloadLaterDialogCoordinator
implements ModalDialogProperties.Controller, DownloadLaterDialogView.Controller,
DownloadDateTimePickerDialogCoordinator.Controller {
private static final long INVALID_START_TIME = -1;
implements ModalDialogProperties.Controller, DownloadLaterDialogView.Controller {
private PropertyModel mDownloadLaterDialogModel;
private DownloadLaterDialogView mCustomView;
private Context mContext;
private ModalDialogManager mModalDialogManager;
private PrefService mPrefService;
private PropertyModel mDialogModel;
private PropertyModelChangeProcessor<PropertyModel, DownloadLaterDialogView, PropertyKey>
mPropertyModelChangeProcessor;
private DownloadLaterDialogController mController;
private final DownloadDateTimePickerDialogCoordinator mDateTimePickerDialog;
@DownloadLaterDialogChoice
private int mDownloadLaterChoice = DownloadLaterDialogChoice.DOWNLOAD_NOW;
/**
* Creates the {@link DownloadLaterDialogCoordinator}.
* @param dateTimePickerDialog The date time selection widget.
*/
public DownloadLaterDialogCoordinator(
@NonNull DownloadDateTimePickerDialogCoordinator dateTimePickerDialog) {
mDateTimePickerDialog = dateTimePickerDialog;
}
/**
* Initializes the download location dialog.
......@@ -63,34 +43,28 @@ public class DownloadLaterDialogCoordinator
/**
* Shows the download later dialog.
* @param context The {@link Context} for the dialog.
* @param activity The activity that provides android {@link Context} to the dialog.
* @param modalDialogManager {@link ModalDialogManager} to control the dialog.
* @param prefService {@link PrefService} to write download later prompt status preference.
* @param model The data model that defines the UI details.
*/
public void showDialog(Context context, ModalDialogManager modalDialogManager,
PrefService prefService, PropertyModel model) {
if (context == null || modalDialogManager == null) {
public void showDialog(
Activity activity, ModalDialogManager modalDialogManager, PropertyModel model) {
if (activity == null || modalDialogManager == null) {
onDismiss(null, DialogDismissalCause.ACTIVITY_DESTROYED);
return;
}
mContext = context;
mModalDialogManager = modalDialogManager;
mPrefService = prefService;
// Set up the download later UI MVC.
mDownloadLaterDialogModel = model;
mCustomView = (DownloadLaterDialogView) LayoutInflater.from(context).inflate(
mCustomView = (DownloadLaterDialogView) LayoutInflater.from(activity).inflate(
R.layout.download_later_dialog, null);
mPropertyModelChangeProcessor =
PropertyModelChangeProcessor.create(mDownloadLaterDialogModel, mCustomView,
DownloadLaterDialogView.Binder::bind, true /*performInitialBind*/);
mDownloadLaterChoice =
model.get(DownloadLaterDialogProperties.DOWNLOAD_TIME_INITIAL_SELECTION);
// Set up the modal dialog.
mDialogModel = getModalDialogModel(context, this);
mModalDialogManager = modalDialogManager;
mDialogModel = getModalDialogModel(activity, this);
mModalDialogManager.showDialog(mDialogModel, ModalDialogManager.ModalDialogType.APP);
}
......@@ -103,10 +77,6 @@ public class DownloadLaterDialogCoordinator
mModalDialogManager.dismissDialog(mDialogModel, dismissalCause);
}
public @DownloadLaterDialogChoice int getChoice() {
return mDownloadLaterChoice;
}
/**
* Destroy the download later dialog.
*/
......@@ -114,13 +84,10 @@ public class DownloadLaterDialogCoordinator
if (mPropertyModelChangeProcessor != null) {
mPropertyModelChangeProcessor.destroy();
}
if (mModalDialogManager != null) {
mModalDialogManager.dismissDialog(
mDialogModel, DialogDismissalCause.DISMISSED_BY_NATIVE);
}
mDateTimePickerDialog.destroy();
}
private PropertyModel getModalDialogModel(
......@@ -136,51 +103,6 @@ public class DownloadLaterDialogCoordinator
.build();
}
private void onPositiveButtonClicked(@DownloadLaterDialogChoice int choice) {
mDownloadLaterChoice = choice;
// Immediately show the date time picker when selecting the "Download later".
if (choice == DownloadLaterDialogChoice.DOWNLOAD_LATER) {
dismissDialog(DialogDismissalCause.ACTION_ON_CONTENT);
showDateTimePicker();
return;
}
// The user select "Download now" or "On wifi", no time is selected.
notifyComplete(INVALID_START_TIME);
}
private void showDateTimePicker() {
long now = System.currentTimeMillis();
// TODO(xingliu): Round up default time to next hour from now.
PropertyModel model =
new PropertyModel.Builder(DownloadDateTimePickerDialogProperties.ALL_KEYS)
.with(DownloadDateTimePickerDialogProperties.STATE, State.DATE)
.with(DownloadDateTimePickerDialogProperties.INITIAL_TIME, now)
.with(DownloadDateTimePickerDialogProperties.MIN_TIME, now)
.build();
mDateTimePickerDialog.showDialog(mContext, mModalDialogManager, model);
}
private void notifyComplete(long time) {
assert mController != null;
updatePromptStatus();
mController.onDownloadLaterDialogComplete(mDownloadLaterChoice, time);
}
private void notifyCancel() {
assert mController != null;
updatePromptStatus();
mController.onDownloadLaterDialogCanceled();
}
private void updatePromptStatus() {
assert mCustomView != null;
assert mPrefService != null;
mPrefService.setInteger(Pref.DOWNLOAD_LATER_PROMPT_STATUS, mCustomView.getPromptStatus());
}
// ModalDialogProperties.Controller implementation.
@Override
public void onClick(PropertyModel model, int buttonType) {
......@@ -200,37 +122,23 @@ public class DownloadLaterDialogCoordinator
@Override
public void onDismiss(PropertyModel model, @DialogDismissalCause int dismissalCause) {
if (dismissalCause == DialogDismissalCause.POSITIVE_BUTTON_CLICKED) {
onPositiveButtonClicked(mDownloadLaterChoice);
@DownloadLaterDialogChoice
int choice = (mCustomView == null) ? DownloadLaterDialogChoice.DOWNLOAD_NOW
: mCustomView.getChoice();
@DownloadLaterPromptStatus
int promptStatus = (mCustomView == null) ? DownloadLaterPromptStatus.SHOW_INITIAL
: mCustomView.getPromptStatus();
assert mController != null;
mController.onDownloadLaterDialogComplete(choice, promptStatus);
return;
}
// Temporary dismiss due to the user clicking the "Edit" to open download location dialog.
if (dismissalCause == DialogDismissalCause.ACTION_ON_CONTENT) return;
notifyCancel();
}
// DownloadDateTimePickerDialogCoordinator.Controller implementation.
@Override
public void onDateTimePicked(long time) {
notifyComplete(time);
}
@Override
public void onDateTimePickerCanceled() {
notifyCancel();
assert mController != null;
mController.onDownloadLaterDialogCanceled();
}
// DownloadLaterDialogView.Controller.
@Override
public void onEditLocationClicked() {
// Ask the controller to decide what to do, even though we can dismiss ourselves here.
assert mController != null;
mController.onEditLocationClicked();
}
@Override
public void onCheckedChanged(int choice) {
mDownloadLaterChoice = choice;
}
}
......@@ -6,16 +6,13 @@ package org.chromium.chrome.browser.download.dialogs;
import android.content.Context;
import android.graphics.Typeface;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.StyleSpan;
import android.util.AttributeSet;
import android.widget.CheckBox;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TextView;
import androidx.annotation.Nullable;
......@@ -32,7 +29,8 @@ import org.chromium.ui.text.SpanApplier.SpanInfo;
/**
* The custom view in the download later dialog.
*/
public class DownloadLaterDialogView extends LinearLayout implements OnCheckedChangeListener {
public class DownloadLaterDialogView
extends LinearLayout implements RadioGroup.OnCheckedChangeListener {
private Controller mController;
private RadioButtonWithDescription mDownloadNow;
......@@ -42,6 +40,9 @@ public class DownloadLaterDialogView extends LinearLayout implements OnCheckedCh
private CheckBox mCheckBox;
private TextView mEditText;
// The item that the user selected in the download later dialog UI.
private @DownloadLaterDialogChoice int mChoice = DownloadLaterDialogChoice.DOWNLOAD_NOW;
/**
* The view binder to propagate events from model to view.
*/
......@@ -71,12 +72,6 @@ public class DownloadLaterDialogView extends LinearLayout implements OnCheckedCh
* Called when the edit location text is clicked.
*/
void onEditLocationClicked();
/**
* Called when the choice radio buttons changed.
* @param choice The choice that the user selected.
*/
void onCheckedChanged(@DownloadLaterDialogChoice int choice);
}
public DownloadLaterDialogView(Context context, @Nullable AttributeSet attrs) {
......@@ -114,11 +109,17 @@ public class DownloadLaterDialogView extends LinearLayout implements OnCheckedCh
mDownloadLater.setChecked(true);
break;
}
mChoice = choice;
}
public @DownloadLaterDialogChoice int getChoice() {
return mChoice;
}
void setCheckbox(@DownloadLaterPromptStatus int promptStatus) {
boolean checked = (promptStatus == DownloadLaterPromptStatus.SHOW_INITIAL)
|| (promptStatus == DownloadLaterPromptStatus.DONT_SHOW);
boolean checked = promptStatus == DownloadLaterPromptStatus.SHOW_INITIAL
|| promptStatus == DownloadLaterPromptStatus.SHOW_PREFERENCE;
mCheckBox.setChecked(checked);
}
......@@ -128,21 +129,21 @@ public class DownloadLaterDialogView extends LinearLayout implements OnCheckedCh
: DownloadLaterPromptStatus.SHOW_PREFERENCE;
}
void setShowEditLocation(@Nullable String locationText) {
void setShowEditLocation(String locationText) {
if (locationText == null) {
mEditText.setVisibility(GONE);
return;
}
final SpannableString editText;
final CharSequence editText;
final SpannableStringBuilder directorySpanBuilder = new SpannableStringBuilder();
directorySpanBuilder.append(locationText);
directorySpanBuilder.setSpan(new StyleSpan(Typeface.BOLD), 0, locationText.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mEditText.setMovementMethod(LinkMovementMethod.getInstance());
NoUnderlineClickableSpan editSpan = new NoUnderlineClickableSpan(
getResources(), (view) -> { onEditLocationClicked(); });
NoUnderlineClickableSpan editSpan = new NoUnderlineClickableSpan(getResources(), (view) -> {
if (mController != null) mController.onEditLocationClicked();
});
editText = SpanApplier.applySpans(
getResources().getString(R.string.download_later_edit_location, locationText),
new SpanInfo("<b>", "</b>", directorySpanBuilder),
......@@ -151,11 +152,6 @@ public class DownloadLaterDialogView extends LinearLayout implements OnCheckedCh
mEditText.setVisibility(VISIBLE);
}
private void onEditLocationClicked() {
assert mController != null : "Please bind the controller first.";
mController.onEditLocationClicked();
}
// RadioGroup.OnCheckedChangeListener overrides.
@Override
public void onCheckedChanged(RadioGroup radioGroup, int index) {
......@@ -168,6 +164,6 @@ public class DownloadLaterDialogView extends LinearLayout implements OnCheckedCh
} else if (mDownloadLater.isChecked()) {
choice = DownloadLaterDialogChoice.DOWNLOAD_LATER;
}
mController.onCheckedChanged(choice);
mChoice = choice;
}
}
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.download.dialogs;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;
......@@ -52,20 +53,20 @@ public class DownloadLocationDialogCoordinator implements ModalDialogProperties.
/**
* Shows the download location dialog.
* @param context The {@link Context} for the dialog.
* @param activity The activity that provides android {@link Context} to the dialog.
* @param modalDialogManager {@link ModalDialogManager} to control the dialog.
* @param totalBytes The total download file size. May be 0 if not available.
* @param dialogType The type of the location dialog.
* @param suggestedPath The suggested file path used by the location dialog.
*/
public void showDialog(Context context, ModalDialogManager modalDialogManager, long totalBytes,
@DownloadLocationDialogType int dialogType, String suggestedPath) {
if (context == null || modalDialogManager == null) {
public void showDialog(Activity activity, ModalDialogManager modalDialogManager,
long totalBytes, @DownloadLocationDialogType int dialogType, String suggestedPath) {
if (activity == null || modalDialogManager == null) {
onDismiss(null, DialogDismissalCause.ACTIVITY_DESTROYED);
return;
}
mContext = context;
mContext = activity;
mModalDialogManager = modalDialogManager;
mTotalBytes = totalBytes;
mDialogType = dialogType;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment