Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions change/react-native-windows-2019-11-05-11-31-02-refresh2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "prerelease",
"comment": "Support refreshControl",
"packageName": "react-native-windows",
"email": "dida@ntdev.microsoft.com",
"commit": "7f7144f6708042a8e4983a143ef2733ac81abea5",
"date": "2019-11-05T19:31:02.270Z"
}
19 changes: 19 additions & 0 deletions packages/playground/Samples/scrollViewSnapSample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,23 @@ import {
Text,
ScrollView,
TouchableOpacity,
RefreshControl,
} from 'react-native';

function wait(timeout: number) {
return new Promise(resolve => {
setTimeout(resolve, timeout);
});
}

export default class Bootstrap extends React.Component<{}, any> {
state = {
horizontalValue: true,
snapToStartValue: false,
snapToEndValue: false,
zoomValue: false,
alignToStartValue: true,
refreshing: false,
};

toggleSwitch1 = (value: boolean) => {
Expand All @@ -44,6 +52,11 @@ export default class Bootstrap extends React.Component<{}, any> {
this.setState({alignToStartValue: value});
};

onRefresh = () => {
this.setState({refreshing: true});
wait(2000).then(() => this.setState({refreshing: false}));
};

makeItems = (nItems: number, styles: Object): Array<any> => {
const items = [];
for (let i = 0; i < nItems; i++) {
Expand Down Expand Up @@ -153,6 +166,12 @@ export default class Bootstrap extends React.Component<{}, any> {
? styles.horizontalScrollViewStyle
: styles.verticalScrollViewStyle
}
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.onRefresh}
/>
}
snapToOffsets={[100.0, 500.0]}
minimumZoomScale={0.1}
maximumZoomScale={2.0}
Expand Down
2 changes: 0 additions & 2 deletions packages/playground/windows/playground/HostingPane.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
<ComboBox x:Name="x_JavaScriptFilename"
Grid.Column="1"
Margin="2,2,2,2"
IsEditable="True"
MinWidth="250"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Expand All @@ -47,7 +46,6 @@
<ComboBox
x:Name="x_ReactAppName"
Grid.Column="3"
IsEditable="True"
Margin="2,2,2,2"
MinWidth="150"
HorizontalAlignment="Stretch"
Expand Down
7 changes: 7 additions & 0 deletions packages/playground/windows/playground/HostingPane.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,13 @@ void HostingPane::InitComboBoxes() {
m_ReactAppNames = ref new Platform::Collections::Vector<String ^>();

x_ReactAppName->ItemsSource = m_ReactAppNames;

// IsEditable is only supported on RS4 or higher
if (Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent(
L"Windows.Foundation.UniversalApiContract", 6)) {
x_ReactAppName->IsEditable = true;
Copy link
Contributor

@acoates-ms acoates-ms Nov 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment for why you are doing this in code vs markup (I'm assuming this is a back compat thing?) #Resolved

x_JavaScriptFilename->IsEditable = true;
}
}

void HostingPane::LoadKnownApps() {
Expand Down
2 changes: 2 additions & 0 deletions vnext/ReactUWP/Base/UwpReactInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <Views/PickerViewManager.h>
#include <Views/PopupViewManager.h>
#include <Views/RawTextViewManager.h>
#include <Views/RefreshControlManager.h>
#include <Views/RootViewManager.h>
#include <Views/ScrollContentViewManager.h>
#include <Views/ScrollViewManager.h>
Expand Down Expand Up @@ -132,6 +133,7 @@ CreateUIManager(
viewManagers.push_back(std::make_unique<ViewViewManager>(instance));
viewManagers.push_back(std::make_unique<VirtualTextViewManager>(instance));
viewManagers.push_back(std::make_unique<WebViewManager>(instance));
viewManagers.push_back(std::make_unique<RefreshControlViewManager>(instance));

// Polyester view managers
viewManagers.push_back(std::make_unique<polyester::ButtonViewManager>(instance));
Expand Down
2 changes: 2 additions & 0 deletions vnext/ReactUWP/ReactUWP.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
<ClInclude Include="Views\PopupViewManager.h" />
<ClInclude Include="Views\RawTextViewManager.h" />
<ClInclude Include="Views\ReactControl.h" />
<ClInclude Include="Views\RefreshControlManager.h" />
<ClInclude Include="Views\RootViewManager.h" />
<ClInclude Include="Views\ScrollContentViewManager.h" />
<ClInclude Include="Views\ScrollViewManager.h" />
Expand Down Expand Up @@ -362,6 +363,7 @@
<ClCompile Include="Views\RawTextViewManager.cpp" />
<ClCompile Include="Views\ReactControl.cpp" />
<ClCompile Include="Views\ReactRootView.cpp" />
<ClCompile Include="Views\RefreshControlManager.cpp" />
<ClCompile Include="Views\RootViewManager.cpp" />
<ClCompile Include="Views\ScrollContentViewManager.cpp" />
<ClCompile Include="Views\ScrollViewManager.cpp" />
Expand Down
8 changes: 6 additions & 2 deletions vnext/ReactUWP/ReactUWP.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,9 @@
<Filter>Views</Filter>
</ClCompile>
<ClCompile Include="Modules\Animated\CalculatedAnimationDriver.cpp" />
<ClCompile Include="Views\SIPEventHandler.cpp" />
<ClCompile Include="Views\RefreshControlManager.cpp">
<Filter>Views</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Modules\DeviceInfoModule.h">
Expand Down Expand Up @@ -645,7 +647,9 @@
<Filter>Modules</Filter>
</ClInclude>
<ClInclude Include="Modules\Animated\CalculatedAnimationDriver.h" />
<ClInclude Include="Views\SIPEventHandler.h" />
<ClInclude Include="Views\RefreshControlManager.h">
<Filter>Views</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="EndPoints\dll\react-native-uwp.arm.def">
Expand Down
22 changes: 22 additions & 0 deletions vnext/ReactUWP/Utils/Helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
#include "pch.h"

#include <Modules/NativeUIManager.h>
#include <winrt\Windows.Foundation.Metadata.h>
#include "Helpers.h"

namespace winrt {
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::Foundation::Metadata;
} // namespace winrt

namespace react {
Expand Down Expand Up @@ -43,5 +45,25 @@ std::int32_t CountOpenPopups() {
return (int32_t)popups.Size();
}

template <uint16_t APIVersion>
bool IsAPIContractVxAvailable() {
static bool isAPIContractVxAvailableInitialized = false;
static bool isAPIContractVxAvailable = false;
if (!isAPIContractVxAvailableInitialized) {
isAPIContractVxAvailableInitialized = true;
isAPIContractVxAvailable =
winrt::ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", APIVersion);
}

return isAPIContractVxAvailable;
}

bool IsAPIContractV6Available() {
return IsAPIContractVxAvailable<6>();
}

bool IsRS4OrHigher() {
return IsAPIContractV6Available();
}
} // namespace uwp
}; // namespace react
2 changes: 2 additions & 0 deletions vnext/ReactUWP/Utils/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ inline typename T asEnum(folly::dynamic const &obj) {

ReactId getViewId(_In_ IReactInstance *instance, winrt::FrameworkElement const &fe);
std::int32_t CountOpenPopups();

bool IsRS4OrHigher();
} // namespace uwp
} // namespace react
120 changes: 120 additions & 0 deletions vnext/ReactUWP/Views/RefreshControlManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "pch.h"

#include "RefreshControlManager.h"

#include <winrt/Windows.UI.Xaml.Shapes.h>

#include <ReactUWP\Utils\Helpers.h>
#include <Views/ShadowNodeBase.h>

namespace winrt {
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::Foundation;
} // namespace winrt

namespace react {
namespace uwp {

class RefreshControlShadowNode : public ShadowNodeBase {
using Super = ShadowNodeBase;

public:
RefreshControlShadowNode(){};
void createView() override;
void updateProperties(const folly::dynamic &&props) override;

private:
winrt::RefreshContainer::RefreshRequested_revoker m_refreshRequestedRevoker{};
winrt::Deferral m_refreshDeferral{nullptr};
};

void RefreshControlShadowNode::createView() {
Super::createView();
if (auto refreshContainer = GetView().try_as<winrt::RefreshContainer>()) {
m_refreshRequestedRevoker =
refreshContainer.RefreshRequested(winrt::auto_revoke, [this](auto &&, winrt::RefreshRequestedEventArgs args) {
auto wkinstance = GetViewManager()->GetReactInstance();
if (auto instance = wkinstance.lock()) {
m_refreshDeferral = args.GetDeferral();
folly::dynamic eventData = folly::dynamic::object();
instance->DispatchEvent(m_tag, "topOnRefresh", std::move(eventData));
}
});
}
}

void RefreshControlShadowNode::updateProperties(const folly::dynamic &&props) {
if (auto refreshContainer = GetView().try_as<winrt::RefreshContainer>()) {
for (const auto &pair : props.items()) {
const std::string &propertyName = pair.first.getString();
if (propertyName == "flexDirection") {
const folly::dynamic &propertyValue = pair.second;
if (propertyValue.isString() && propertyValue.asString() == "column") { // vertical scrollView
refreshContainer.PullDirection(winrt::RefreshPullDirection::TopToBottom);
} else {
refreshContainer.PullDirection(winrt::RefreshPullDirection::LeftToRight);
}
} else if (propertyName == "refreshing") {
const folly::dynamic &propertyValue = pair.second;
if (propertyValue.isBool()) {
bool refreshing = propertyValue.asBool();
if (!refreshing && m_refreshDeferral) {
m_refreshDeferral.Complete();
m_refreshDeferral = nullptr;
}
}
}
}
}

Super::updateProperties(std::move(props));
}

RefreshControlViewManager::RefreshControlViewManager(const std::shared_ptr<IReactInstance> &reactInstance)
: Super(reactInstance) {}

facebook::react::ShadowNode *RefreshControlViewManager::createShadow() const {
return new RefreshControlShadowNode();
}

const char *RefreshControlViewManager::GetName() const {
return "RCTRefreshControl";
}

XamlView RefreshControlViewManager::CreateViewCore(int64_t tag) {
if (IsRS4OrHigher()) {
// refreshContainer is supported >= RS4
return winrt::RefreshContainer();
} else {
// just return a grid if refreshContainer is not supported
return winrt::Grid();
}
}

void RefreshControlViewManager::AddView(XamlView parent, XamlView child, int64_t index) {
if (auto refreshContainer = parent.try_as<winrt::RefreshContainer>()) {
refreshContainer.Content(child.as<winrt::ScrollViewer>());
} else if (auto grid = parent.try_as<winrt::Grid>()) {
grid.Children().Append(child.as<winrt::ScrollViewer>());
}
}

folly::dynamic RefreshControlViewManager::GetNativeProps() const {
auto props = Super::GetNativeProps();

props.update(folly::dynamic::object("refreshing", "boolean"));

return props;
}

folly::dynamic RefreshControlViewManager::GetExportedCustomDirectEventTypeConstants() const {
auto directEvents = Super::GetExportedCustomDirectEventTypeConstants();
directEvents["topOnRefresh"] = folly::dynamic::object("registrationName", "onRefresh");
return directEvents;
}
} // namespace uwp
} // namespace react
29 changes: 29 additions & 0 deletions vnext/ReactUWP/Views/RefreshControlManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#include <Views/FrameworkElementViewManager.h>

namespace react {
namespace uwp {

class RefreshControlViewManager : public FrameworkElementViewManager {
using Super = FrameworkElementViewManager;

public:
RefreshControlViewManager(const std::shared_ptr<IReactInstance> &reactInstance);

facebook::react::ShadowNode *createShadow() const override;

const char *GetName() const override;
folly::dynamic GetNativeProps() const override;
folly::dynamic GetExportedCustomDirectEventTypeConstants() const override;

protected:
XamlView CreateViewCore(int64_t tag) override;
void AddView(XamlView parent, XamlView child, int64_t index) override;
};

} // namespace uwp
} // namespace react
Loading