Commit 858fc730 authored by sczs's avatar sczs Committed by Commit Bot

[ios] Prepares for new RecentTabsVC creation.

- Creates a RecentTabsTableViewController constants file.
- Creates a file for RecentTabsTableViewControllerDelegate protocol.
- Creates Protocol RecentTabsTableViewControllerInterface, this includes all the public
RecentTabsTableViewController methods.
- Renames RecentTabsTableViewController to LegacyRecentTabsTableViewController.
- Small cleanup of unused imports.


Bug: 805013
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: Ie682653c2154e22776b0e991db56d52f6d5aab20
Reviewed-on: https://chromium-review.googlesource.com/896923
Commit-Queue: Sergio Collazos <sczs@chromium.org>
Reviewed-by: default avatarRohit Rao <rohitrao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#536913}
parent 73354fbe
......@@ -28,7 +28,7 @@
#import "ios/chrome/browser/ui/ntp/incognito_view_controller.h"
#import "ios/chrome/browser/ui/ntp/new_tab_page_bar_item.h"
#import "ios/chrome/browser/ui/ntp/new_tab_page_view.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/rtl_geometry.h"
#include "ios/chrome/browser/ui/toolbar/toolbar_model_ios.h"
#include "ios/chrome/browser/ui/ui_util.h"
......
......@@ -7,14 +7,17 @@ source_set("recent_tabs") {
sources = [
"closed_tabs_observer_bridge.h",
"closed_tabs_observer_bridge.mm",
"legacy_recent_tabs_table_coordinator.h",
"legacy_recent_tabs_table_coordinator.mm",
"legacy_recent_tabs_table_view_controller.h",
"legacy_recent_tabs_table_view_controller.mm",
"legacy_recent_tabs_table_view_controller_delegate.h",
"recent_tabs_constants.h",
"recent_tabs_constants.mm",
"recent_tabs_handset_coordinator.h",
"recent_tabs_handset_coordinator.mm",
"recent_tabs_handset_view_controller.h",
"recent_tabs_handset_view_controller.mm",
"recent_tabs_table_coordinator.h",
"recent_tabs_table_coordinator.mm",
"recent_tabs_table_view_controller.h",
"recent_tabs_table_view_controller.mm",
"sessions_sync_user_state.h",
"synced_sessions.h",
"synced_sessions.mm",
......
......@@ -4,8 +4,6 @@
#import "ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_COORDINATOR_H_
#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_COORDINATOR_H_
#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_LEGACY_RECENT_TABS_TABLE_COORDINATOR_H_
#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_LEGACY_RECENT_TABS_TABLE_COORDINATOR_H_
#import <UIKit/UIKit.h>
......@@ -16,16 +16,16 @@ class ChromeBrowserState;
@protocol ApplicationCommands;
@protocol RecentTabsHandsetViewControllerCommand;
@class RecentTabsTableViewController;
@class LegacyRecentTabsTableViewController;
@protocol UrlLoader;
// RecentTabsTableCoordinator controls the RecentTabTableViewDataSource, based
// on the user's signed-in and chrome-sync states.
// LegacyRecentTabsTableCoordinator controls the RecentTabTableViewDataSource,
// based on the user's signed-in and chrome-sync states.
//
// RecentTabsTableCoordinator listens for notifications about Chrome Sync
// LegacyRecentTabsTableCoordinator listens for notifications about Chrome Sync
// and ChromeToDevice and changes/updates the view accordingly.
//
@interface RecentTabsTableCoordinator : ChromeCoordinator
@interface LegacyRecentTabsTableCoordinator : ChromeCoordinator
// Command handler for the command sent when the device is a handset. Nil
// otherwise.
......@@ -38,7 +38,8 @@ class ChromeBrowserState;
dispatcher:(id<ApplicationCommands>)dispatcher;
// Private initializer, exposed for testing.
- (instancetype)initWithController:(RecentTabsTableViewController*)controller
- (instancetype)initWithController:
(LegacyRecentTabsTableViewController*)controller
browserState:(ios::ChromeBrowserState*)browserState
NS_DESIGNATED_INITIALIZER;
......@@ -54,4 +55,4 @@ class ChromeBrowserState;
@end
#endif // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_COORDINATOR_H_
#endif // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_LEGACY_RECENT_TABS_TABLE_COORDINATOR_H_
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_coordinator.h"
#include <memory>
......@@ -17,21 +17,22 @@
#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
#import "ios/chrome/browser/sync/synced_sessions_bridge.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_view_controller.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_view_controller_delegate.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@interface RecentTabsTableCoordinator ()<
@interface LegacyRecentTabsTableCoordinator ()<
ClosedTabsObserving,
SyncedSessionsObserver,
RecentTabsTableViewControllerDelegate> {
LegacyRecentTabsTableViewControllerDelegate> {
std::unique_ptr<synced_sessions::SyncedSessionsObserverBridge>
_syncedSessionsObserver;
std::unique_ptr<recent_tabs::ClosedTabsObserverBridge> _closedTabsObserver;
SessionsSyncUserState _userState;
RecentTabsTableViewController* _tableViewController;
LegacyRecentTabsTableViewController* _tableViewController;
ios::ChromeBrowserState* _browserState; // Weak.
}
......@@ -53,21 +54,22 @@
// The controller for RecentTabs panel that is added to the NewTabPage
// Instantiate a UITableView and a UITableViewController, and notifies the
// UITableViewController of any signed in state change.
@implementation RecentTabsTableCoordinator
@implementation LegacyRecentTabsTableCoordinator
@synthesize handsetCommandHandler = _handsetCommandHandler;
- (instancetype)initWithLoader:(id<UrlLoader>)loader
browserState:(ios::ChromeBrowserState*)browserState
dispatcher:(id<ApplicationCommands>)dispatcher {
return [self initWithController:[[RecentTabsTableViewController alloc]
return [self initWithController:[[LegacyRecentTabsTableViewController alloc]
initWithBrowserState:browserState
loader:loader
dispatcher:dispatcher]
browserState:browserState];
}
- (instancetype)initWithController:(RecentTabsTableViewController*)controller
- (instancetype)initWithController:
(LegacyRecentTabsTableViewController*)controller
browserState:(ios::ChromeBrowserState*)browserState {
self = [super initWithBaseViewController:nil browserState:browserState];
if (self) {
......@@ -205,7 +207,7 @@
#pragma mark - RecentTabsTableViewControllerDelegate
- (void)refreshSessionsViewRecentTabsTableViewController:
(RecentTabsTableViewController*)controller {
(LegacyRecentTabsTableViewController*)controller {
[self refreshSessionsView];
}
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_LEGACY_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_LEGACY_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
#import <UIKit/UIKit.h>
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller_interface.h"
// Controls the content of a UITableView.
//
// The UITableView can contain the following different sections:
// A/ Closed tabs section.
// This section lists all the local tabs that were recently closed.
// A*/ Separator section.
// This section contains only a single cell that acts as a separator.
// B/ Other Devices section.
// Depending on the user state, the section will either contain a view
// offering the user to sign in, a view to activate sync, or a view to inform
// the user that they can turn on sync on other devices.
// C/ Session section.
// This section shows the sessions from other devices.
//
// Section A is always present, followed by section A*.
// Depending on the user sync state, either section B or section C will be
// presented.
@interface LegacyRecentTabsTableViewController
: UITableViewController<UIGestureRecognizerDelegate,
RecentTabsTableViewControllerInterface>
@end
#endif // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_LEGACY_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_view_controller.h"
#include <memory>
......@@ -26,6 +26,8 @@
#include "ios/chrome/browser/ui/commands/application_commands.h"
#import "ios/chrome/browser/ui/commands/show_signin_command.h"
#import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_view_controller_delegate.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_view_controller.h"
#include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.h"
......@@ -53,12 +55,6 @@
#error "This file requires ARC support."
#endif
// Key for saving collapsed session state in the UserDefaults.
NSString* const kCollapsedSectionsKey = @"ChromeRecentTabsCollapsedSections";
// Accessibility identifier for the main view.
NSString* const kRecentTabsTableViewControllerAccessibilityIdentifier =
@"recent_tabs_view_controller";
namespace {
// Key for saving whether the Other Device section is collapsed.
......@@ -98,9 +94,9 @@ enum CellType {
} // namespace
@interface RecentTabsTableViewController ()<SigninPromoViewConsumer,
SigninPresenter,
SyncPresenter> {
@interface LegacyRecentTabsTableViewController ()<SigninPromoViewConsumer,
SigninPresenter,
SyncPresenter> {
ios::ChromeBrowserState* _browserState; // weak
// The service that manages the recently closed tabs.
sessions::TabRestoreService* _tabRestoreService; // weak
......@@ -165,7 +161,7 @@ enum CellType {
@end
@implementation RecentTabsTableViewController
@implementation LegacyRecentTabsTableViewController
@synthesize delegate = delegate_;
@synthesize dispatcher = _dispatcher;
......@@ -388,7 +384,7 @@ enum CellType {
}
- (void)showFullHistory {
__weak RecentTabsTableViewController* weakSelf = self;
__weak LegacyRecentTabsTableViewController* weakSelf = self;
ProceduralBlock openHistory = ^{
[weakSelf.dispatcher showHistory];
};
......@@ -472,8 +468,8 @@ enum CellType {
}
- (void)setSection:(NSString*)sectionKey collapsed:(BOOL)collapsed {
// TODO(jif): Store in the browser state preference instead of NSUserDefaults.
// crbug.com/419346.
// TODO(crbug.com/419346): Store in the browser state preference instead of
// NSUserDefaults.
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
NSDictionary* collapsedSections =
[defaults dictionaryForKey:kCollapsedSectionsKey];
......@@ -617,7 +613,7 @@ enum CellType {
params:params];
// Fill the sheet/popover with buttons.
__weak RecentTabsTableViewController* weakSelf = self;
__weak LegacyRecentTabsTableViewController* weakSelf = self;
// "Open all tabs" button.
NSString* openAllButtonLabel =
......@@ -847,7 +843,7 @@ enum CellType {
// Sets constraints on the subview.
[subview setTranslatesAutoresizingMaskIntoConstraints:NO];
NSDictionary* viewsDictionary = @{ @"view" : subview };
NSDictionary* viewsDictionary = @{@"view" : subview};
// This set of constraints should match the constraints set on the
// RecentlyClosedSectionFooter.
// clang-format off
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <Foundation/Foundation.h>
// Protocol used by LegacyRecentTabsTableViewController to communicate to its
// Coordinator.
@protocol LegacyRecentTabsTableViewControllerDelegate<NSObject>
// Tells the delegate to refresh the session view.
- (void)refreshSessionsViewRecentTabsTableViewController:
(LegacyRecentTabsTableViewController*)controller;
@end
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
#import <Foundation/Foundation.h>
// Key for saving collapsed session state in the UserDefaults.
extern NSString* const kCollapsedSectionsKey;
// Accessibility identifier for the main view.
extern NSString* const kRecentTabsTableViewControllerAccessibilityIdentifier;
#endif // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
NSString* const kCollapsedSectionsKey = @"ChromeRecentTabsCollapsedSections";
NSString* const kRecentTabsTableViewControllerAccessibilityIdentifier =
@"recent_tabs_view_controller";
......@@ -6,8 +6,8 @@
#include "base/ios/block_types.h"
#include "base/logging.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_handset_view_controller.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
......@@ -18,7 +18,7 @@
@property(nonatomic, strong)
RecentTabsHandsetViewController* recentTabsViewController;
@property(nonatomic, strong) RecentTabsTableCoordinator* tableCoordinator;
@property(nonatomic, strong) LegacyRecentTabsTableCoordinator* tableCoordinator;
// Completion block called once the recentTabsViewController is dismissed.
@property(nonatomic, copy) ProceduralBlock completion;
......@@ -37,9 +37,9 @@
DCHECK(self.browserState);
self.tableCoordinator =
[[RecentTabsTableCoordinator alloc] initWithLoader:self.loader
browserState:self.browserState
dispatcher:self.dispatcher];
[[LegacyRecentTabsTableCoordinator alloc] initWithLoader:self.loader
browserState:self.browserState
dispatcher:self.dispatcher];
self.tableCoordinator.handsetCommandHandler = self;
[self.tableCoordinator start];
......
......@@ -6,7 +6,7 @@
#include "base/logging.h"
#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.h"
#import "ios/chrome/browser/ui/uikit_ui_util.h"
#import "ios/chrome/browser/ui/util/constraints_ui_util.h"
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_coordinator.h"
#import <UIKit/UIKit.h>
......@@ -19,8 +19,7 @@
#include "ios/chrome/browser/sync/sync_setup_service.h"
#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
#include "ios/chrome/browser/sync/sync_setup_service_mock.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/legacy_recent_tabs_table_view_controller.h"
#include "ios/chrome/test/block_cleanup_test.h"
#include "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
#include "ios/web/public/test/test_web_thread_bundle.h"
......@@ -124,8 +123,8 @@ class RecentTabsTableCoordinatorTest : public BlockCleanupTest {
EXPECT_CALL(*sync_service, GetOpenTabsUIDelegate())
.WillRepeatedly(Return(nullptr));
mock_table_view_controller_ =
[OCMockObject niceMockForClass:[RecentTabsTableViewController class]];
mock_table_view_controller_ = [OCMockObject
niceMockForClass:[LegacyRecentTabsTableViewController class]];
}
void TearDown() override {
......@@ -179,8 +178,8 @@ class RecentTabsTableCoordinatorTest : public BlockCleanupTest {
chrome_browser_state_.get()));
EXPECT_CALL(*sync_service, AddObserver(_)).Times(AtLeast(1));
EXPECT_CALL(*sync_service, RemoveObserver(_)).Times(AtLeast(1));
controller_ = [[RecentTabsTableCoordinator alloc]
initWithController:(RecentTabsTableViewController*)
controller_ = [[LegacyRecentTabsTableCoordinator alloc]
initWithController:(LegacyRecentTabsTableViewController*)
mock_table_view_controller_
browserState:chrome_browser_state_.get()];
[controller_ start];
......@@ -196,7 +195,7 @@ class RecentTabsTableCoordinatorTest : public BlockCleanupTest {
// Must be declared *after* |chrome_browser_state_| so it can outlive it.
OCMockObject* mock_table_view_controller_;
RecentTabsTableCoordinator* controller_;
LegacyRecentTabsTableCoordinator* controller_;
};
TEST_F(RecentTabsTableCoordinatorTest, TestConstructorDestructor) {
......
......@@ -11,7 +11,7 @@
#include "base/test/scoped_feature_list.h"
#include "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
#include "ios/chrome/browser/ui/ui_util.h"
#include "ios/chrome/grit/ios_strings.h"
#import "ios/chrome/test/app/tab_test_util.h"
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
#import <Foundation/Foundation.h>
#import "ios/chrome/browser/ui/ntp/new_tab_page_panel_protocol.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_coordinator.h"
#import "ios/chrome/browser/ui/ntp/recent_tabs/sessions_sync_user_state.h"
namespace sessions {
class TabRestoreService;
}
namespace ios {
class ChromeBrowserState;
}
namespace sessions {
class TabRestoreService;
}
@protocol ApplicationCommands;
@protocol RecentTabsHandsetViewControllerCommand;
@protocol LegacyRecentTabsTableViewControllerDelegate;
@protocol UrlLoader;
// Key for saving collapsed session state in the UserDefaults.
extern NSString* const kCollapsedSectionsKey;
// Accessibility identifier for the main view.
extern NSString* const kRecentTabsTableViewControllerAccessibilityIdentifier;
@protocol RecentTabsTableViewControllerDelegate<NSObject>
// Tells the delegate to refresh the session view.
- (void)refreshSessionsViewRecentTabsTableViewController:
(RecentTabsTableViewController*)controller;
@end
// Controls the content of a UITableView.
//
// The UITableView can contain the following different sections:
// A/ Closed tabs section.
// This section lists all the local tabs that were recently closed.
// A*/ Separator section.
// This section contains only a single cell that acts as a separator.
// B/ Other Devices section.
// Depending on the user state, the section will either contain a view
// offering the user to sign in, a view to activate sync, or a view to inform
// the user that they can turn on sync on other devices.
// C/ Session section.
// This section shows the sessions from other devices.
//
// Section A is always present, followed by section A*.
// Depending on the user sync state, either section B or section C will be
// presented.
@interface RecentTabsTableViewController
: UITableViewController<UIGestureRecognizerDelegate>
@property(nonatomic, weak) id<RecentTabsTableViewControllerDelegate> delegate;
@property(nonatomic, weak) id<RecentTabsHandsetViewControllerCommand>
handsetCommandHandler;
// RecentTabs TableViewController public interface.
@protocol RecentTabsTableViewControllerInterface<NSObject>
// Designated initializer. The controller opens link with |loader|.
// |browserState|
......@@ -76,6 +42,12 @@ extern NSString* const kRecentTabsTableViewControllerAccessibilityIdentifier;
// Dismisses any outstanding modal user interface elements.
- (void)dismissModals;
@end
// RecentTabsTableViewControllerDelegate delegate.
@property(nonatomic, weak) id<LegacyRecentTabsTableViewControllerDelegate>
delegate;
#endif // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
// RecentTabsHandsetViewControllerCommand delegate.
@property(nonatomic, weak) id<RecentTabsHandsetViewControllerCommand>
handsetCommandHandler;
@end
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