add gs
This commit is contained in:
+41
@@ -0,0 +1,41 @@
|
||||
--[[
|
||||
Connects to GuiService's browser close callback to retry purchase after upsell
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local ExternalEventConnection = require(script.Parent.ExternalEventConnection)
|
||||
|
||||
local retryAfterUpsell = require(script.Parent.Parent.Parent.Thunks.retryAfterUpsell)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local function BrowserPurchaseFinishedConnector(props)
|
||||
local onBrowserWindowClosed = props.onBrowserWindowClosed
|
||||
|
||||
--[[
|
||||
CLILUACORE-309: The browser window closing is the ONLY
|
||||
indication we have about when the user finished interacting
|
||||
with the upsell flow on desktop.
|
||||
]]
|
||||
return Roact.createElement(ExternalEventConnection, {
|
||||
event = GuiService.BrowserWindowClosed,
|
||||
callback = onBrowserWindowClosed,
|
||||
})
|
||||
end
|
||||
|
||||
local function mapDispatchToProps(dispatch)
|
||||
return {
|
||||
onBrowserWindowClosed = function()
|
||||
dispatch(retryAfterUpsell())
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
BrowserPurchaseFinishedConnector = connectToStore(
|
||||
nil,
|
||||
mapDispatchToProps
|
||||
)(BrowserPurchaseFinishedConnector)
|
||||
|
||||
return BrowserPurchaseFinishedConnector
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
--[[
|
||||
Connects relevant Roblox engine events to the rodux store
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local UpsellFlow = require(script.Parent.Parent.Parent.UpsellFlow)
|
||||
|
||||
local MarketplaceServiceEventConnector = require(script.Parent.MarketplaceServiceEventConnector)
|
||||
local GamepadInputConnector = require(script.Parent.GamepadInputConnector)
|
||||
|
||||
local BrowserPurchaseFinishedConnector = require(script.Parent.BrowserPurchaseFinishedConnector)
|
||||
local NativePurchaseFinishedConnector = require(script.Parent.NativePurchaseFinishedConnector)
|
||||
|
||||
local getUpsellFlow = require(script.Parent.Parent.Parent.NativeUpsell.getUpsellFlow)
|
||||
|
||||
local function EventConnections()
|
||||
local upsellConnector
|
||||
local upsellFlow = getUpsellFlow(UserInputService:GetPlatform())
|
||||
if upsellFlow == UpsellFlow.Web then
|
||||
upsellConnector = Roact.createElement(BrowserPurchaseFinishedConnector)
|
||||
elseif upsellFlow == UpsellFlow.Mobile then
|
||||
upsellConnector = Roact.createElement(NativePurchaseFinishedConnector)
|
||||
end
|
||||
|
||||
return Roact.createElement("Folder", {}, {
|
||||
MarketPlaceServiceEventConnector = Roact.createElement(MarketplaceServiceEventConnector),
|
||||
GamepadInputConnector = Roact.createElement(GamepadInputConnector),
|
||||
UpsellFinishedConnector = upsellConnector,
|
||||
})
|
||||
end
|
||||
|
||||
return EventConnections
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
--[[
|
||||
A component that establishes a connection to a Roblox event when it is rendered.
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local ExternalEventConnection = Roact.Component:extend("ExternalEventConnection")
|
||||
|
||||
function ExternalEventConnection:init()
|
||||
self.connection = nil
|
||||
end
|
||||
|
||||
--[[
|
||||
Render the child component so that ExternalEventConnections can be nested like so:
|
||||
|
||||
Roact.createElement(ExternalEventConnection, {
|
||||
event = UserInputService.InputBegan,
|
||||
callback = inputBeganCallback,
|
||||
}, {
|
||||
Roact.createElement(ExternalEventConnection, {
|
||||
event = UserInputService.InputEnded,
|
||||
callback = inputChangedCallback,
|
||||
})
|
||||
})
|
||||
]]
|
||||
function ExternalEventConnection:render()
|
||||
return Roact.oneChild(self.props[Roact.Children])
|
||||
end
|
||||
|
||||
function ExternalEventConnection:didMount()
|
||||
local event = self.props.event
|
||||
local callback = self.props.callback
|
||||
|
||||
self.connection = event:Connect(callback)
|
||||
end
|
||||
|
||||
function ExternalEventConnection:didUpdate(oldProps)
|
||||
if self.props.event ~= oldProps.event or self.props.callback ~= oldProps.callback then
|
||||
self.connection:Disconnect()
|
||||
|
||||
self.connection = self.props.event:Connect(self.props.callback)
|
||||
end
|
||||
end
|
||||
|
||||
function ExternalEventConnection:willUnmount()
|
||||
self.connection:Disconnect()
|
||||
|
||||
self.connection = nil
|
||||
end
|
||||
|
||||
return ExternalEventConnection
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
--[[
|
||||
Sets whether or not gamepad buttons should be shown, based on recently
|
||||
received inputs
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local ExternalEventConnection = require(script.Parent.ExternalEventConnection)
|
||||
|
||||
local SetGamepadEnabled = require(script.Parent.Parent.Parent.Actions.SetGamepadEnabled)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local gamepadInputs = {
|
||||
[Enum.UserInputType.Gamepad1] = true,
|
||||
[Enum.UserInputType.Gamepad2] = true,
|
||||
[Enum.UserInputType.Gamepad3] = true,
|
||||
[Enum.UserInputType.Gamepad4] = true,
|
||||
}
|
||||
|
||||
local thumbstickInputs = {
|
||||
[Enum.KeyCode.Thumbstick1] = true,
|
||||
[Enum.KeyCode.Thumbstick2] = true,
|
||||
}
|
||||
|
||||
--[[
|
||||
Returns whether or not input changed, and what its new value is
|
||||
|
||||
UserInputService.InputChanged event fires very frequently when moving
|
||||
the mouse or thumbsticks: we try to early-out if nothing changed so that
|
||||
we don't send hundreds of dispatches through the store
|
||||
]]
|
||||
local function didInputChange(isGamepadEnabled, inputObject)
|
||||
local newEnabledStatus = nil
|
||||
|
||||
if gamepadInputs[inputObject.UserInputType] then
|
||||
if thumbstickInputs[inputObject.KeyCode] then
|
||||
local position = inputObject.Position
|
||||
|
||||
if math.abs(position.X) > 0.1 or math.abs(position.Z) > 0.1 or math.abs(position.Y) > 0.1 then
|
||||
newEnabledStatus = true
|
||||
end
|
||||
else
|
||||
newEnabledStatus = true
|
||||
end
|
||||
else
|
||||
newEnabledStatus = false
|
||||
end
|
||||
|
||||
if newEnabledStatus ~= nil and newEnabledStatus ~= isGamepadEnabled then
|
||||
return true, newEnabledStatus
|
||||
end
|
||||
|
||||
return false, isGamepadEnabled
|
||||
end
|
||||
|
||||
local function GamepadInputConnector(props)
|
||||
local gamepadEnabled = props.gamepadEnabled
|
||||
local inputChanged = props.inputChanged
|
||||
|
||||
local dispatchOnChange = function (inputObject)
|
||||
local didChange, newEnabledStatus = didInputChange(gamepadEnabled, inputObject)
|
||||
|
||||
if didChange then
|
||||
inputChanged(newEnabledStatus)
|
||||
end
|
||||
end
|
||||
|
||||
return Roact.createElement(ExternalEventConnection, {
|
||||
event = UserInputService.InputChanged,
|
||||
callback = dispatchOnChange,
|
||||
}, {
|
||||
Roact.createElement(ExternalEventConnection, {
|
||||
event = UserInputService.InputBegan,
|
||||
callback = dispatchOnChange,
|
||||
})
|
||||
})
|
||||
end
|
||||
|
||||
local function mapStateToProps(state)
|
||||
return {
|
||||
gamepadEnabled = state.gamepadEnabled,
|
||||
}
|
||||
end
|
||||
|
||||
local function mapDispatchToProps(dispatch)
|
||||
return {
|
||||
inputChanged = function(newEnabledStatus)
|
||||
dispatch(SetGamepadEnabled(newEnabledStatus))
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
GamepadInputConnector = connectToStore(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(GamepadInputConnector)
|
||||
|
||||
return GamepadInputConnector
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
--[[
|
||||
LayoutValuesConsumer will extract the LayoutValues object
|
||||
from context and pass it into the given render callback
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local LayoutValuesKey = require(script.Parent.Parent.Parent.LayoutValuesKey)
|
||||
|
||||
local LayoutValuesConsumer = Roact.Component:extend("LayoutValuesConsumer")
|
||||
|
||||
function LayoutValuesConsumer:render()
|
||||
local service = self._context[LayoutValuesKey]
|
||||
|
||||
return self.props.render(service)
|
||||
end
|
||||
|
||||
return LayoutValuesConsumer
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
--[[
|
||||
LayoutValuesProvider is a simple wrapper component that injects the
|
||||
specified services into context
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local LayoutValuesKey = require(script.Parent.Parent.Parent.LayoutValuesKey)
|
||||
|
||||
local LayoutValuesProvider = Roact.Component:extend("LayoutValuesProvider")
|
||||
|
||||
function LayoutValuesProvider:init(props)
|
||||
assert(type(props.layoutValues) == "table", "Expected required prop 'layoutValues' to be a table")
|
||||
assert(type(props.render) == "function", "Expected prop 'render' to be a function")
|
||||
|
||||
self._context[LayoutValuesKey] = props.layoutValues
|
||||
end
|
||||
|
||||
function LayoutValuesProvider:render()
|
||||
return self.props.render()
|
||||
end
|
||||
|
||||
return LayoutValuesProvider
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
LocalizationContextConsumer will extract the localization context
|
||||
object from Roact context and provide it to the given render callback
|
||||
|
||||
Used for components that need to perform localization using this
|
||||
project's LocalizationService
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local LocalizationContextKey = require(script.Parent.Parent.Parent.LocalizationContextKey)
|
||||
|
||||
local LocalizationContextConsumer = Roact.Component:extend("LocalizationContextConsumer")
|
||||
|
||||
function LocalizationContextConsumer:render()
|
||||
local localizationContext = self._context[LocalizationContextKey]
|
||||
|
||||
return self.props.render(localizationContext)
|
||||
end
|
||||
|
||||
return LocalizationContextConsumer
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
--[[
|
||||
LocalizationContextProvider is a simple wrapper component that injects the
|
||||
specified services into context
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local LocalizationContextKey = require(script.Parent.Parent.Parent.LocalizationContextKey)
|
||||
|
||||
local LocalizationContextProvider = Roact.Component:extend("LocalizationContextProvider")
|
||||
|
||||
function LocalizationContextProvider:init(props)
|
||||
assert(props.localizationContext, "Missing required prop 'localizationContext'")
|
||||
assert(props.render, "Missing required prop 'render'")
|
||||
|
||||
self._context[LocalizationContextKey] = props.localizationContext
|
||||
end
|
||||
|
||||
function LocalizationContextProvider:render()
|
||||
return self.props.render(LocalizationContextKey)
|
||||
end
|
||||
|
||||
return LocalizationContextProvider
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
--[[
|
||||
Connects Rodux store to external MarketplaceService events
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local MarketplaceService = game:GetService("MarketplaceService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local ExternalEventConnection = require(script.Parent.ExternalEventConnection)
|
||||
|
||||
local PurchaseError = require(script.Parent.Parent.Parent.PurchaseError)
|
||||
|
||||
local ErrorOccurred = require(script.Parent.Parent.Parent.Actions.ErrorOccurred)
|
||||
|
||||
local completePurchase = require(script.Parent.Parent.Parent.Thunks.completePurchase)
|
||||
local initiatePurchase = require(script.Parent.Parent.Parent.Thunks.initiatePurchase)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local function MarketplaceServiceEventConnector(props)
|
||||
local onPurchaseRequest = props.onPurchaseRequest
|
||||
local onProductPurchaseRequest = props.onProductPurchaseRequest
|
||||
local onPurchaseGamePassRequest = props.onPurchaseGamePassRequest
|
||||
local onServerPurchaseVerification = props.onServerPurchaseVerification
|
||||
|
||||
return Roact.createElement(ExternalEventConnection, {
|
||||
event = MarketplaceService.PromptPurchaseRequested,
|
||||
callback = onPurchaseRequest,
|
||||
}, {
|
||||
Roact.createElement(ExternalEventConnection, {
|
||||
event = MarketplaceService.PromptProductPurchaseRequested,
|
||||
callback = onProductPurchaseRequest,
|
||||
}, {
|
||||
Roact.createElement(ExternalEventConnection, {
|
||||
event = MarketplaceService.PromptGamePassPurchaseRequested,
|
||||
callback = onPurchaseGamePassRequest,
|
||||
}, {
|
||||
Roact.createElement(ExternalEventConnection, {
|
||||
event = MarketplaceService.ServerPurchaseVerification,
|
||||
callback = onServerPurchaseVerification,
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
end
|
||||
|
||||
MarketplaceServiceEventConnector = connectToStore(nil,
|
||||
function(dispatch)
|
||||
local function onPurchaseRequest(player, assetId, equipIfPurchased, currencyType)
|
||||
dispatch(initiatePurchase(assetId, Enum.InfoType.Asset, equipIfPurchased))
|
||||
end
|
||||
|
||||
local function onProductPurchaseRequest(player, productId, equipIfPurchased, currencyType)
|
||||
dispatch(initiatePurchase(productId, Enum.InfoType.Product, equipIfPurchased))
|
||||
end
|
||||
|
||||
local function onPurchaseGamePassRequest(player, gamePassId)
|
||||
dispatch(initiatePurchase(gamePassId, Enum.InfoType.GamePass, false))
|
||||
end
|
||||
|
||||
-- Specific to purchasing dev products
|
||||
local function onServerPurchaseVerification(serverResponseTable)
|
||||
if not serverResponseTable then
|
||||
dispatch(ErrorOccurred(PurchaseError.UnknownFailure))
|
||||
else
|
||||
dispatch(completePurchase())
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
onPurchaseRequest = onPurchaseRequest,
|
||||
onProductPurchaseRequest = onProductPurchaseRequest,
|
||||
onPurchaseGamePassRequest = onPurchaseGamePassRequest,
|
||||
onServerPurchaseVerification = onServerPurchaseVerification,
|
||||
}
|
||||
end)(MarketplaceServiceEventConnector)
|
||||
|
||||
return MarketplaceServiceEventConnector
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
--[[
|
||||
Connects to MarketplaceService's callback for completing a native purchase, so that we can
|
||||
retry after an upsell purchase was processed
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local MarketplaceService = game:GetService("MarketplaceService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
local ExternalEventConnection = require(script.Parent.ExternalEventConnection)
|
||||
|
||||
local ErrorOccurred = require(script.Parent.Parent.Parent.Actions.ErrorOccurred)
|
||||
|
||||
local PurchaseError = require(script.Parent.Parent.Parent.PurchaseError)
|
||||
|
||||
local retryAfterUpsell = require(script.Parent.Parent.Parent.Thunks.retryAfterUpsell)
|
||||
|
||||
local connectToStore = require(script.Parent.Parent.Parent.connectToStore)
|
||||
|
||||
local function NativePurchaseFinishedConnector(props)
|
||||
local nativePurchaseFinished = props.nativePurchaseFinished
|
||||
|
||||
return Roact.createElement(ExternalEventConnection, {
|
||||
event = MarketplaceService.NativePurchaseFinished,
|
||||
callback = nativePurchaseFinished,
|
||||
})
|
||||
end
|
||||
|
||||
local function mapDispatchToProps(dispatch)
|
||||
return {
|
||||
nativePurchaseFinished = function(player, productId, wasPurchased)
|
||||
if wasPurchased then
|
||||
dispatch(retryAfterUpsell())
|
||||
else
|
||||
dispatch(ErrorOccurred(PurchaseError.InvalidFunds))
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
NativePurchaseFinishedConnector = connectToStore(
|
||||
nil,
|
||||
mapDispatchToProps
|
||||
)(NativePurchaseFinishedConnector)
|
||||
|
||||
return NativePurchaseFinishedConnector
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local LocalizationService = require(script.Parent.Parent.Parent.Localization.LocalizationService)
|
||||
local LocalizationContextConsumer = require(script.Parent.LocalizationContextConsumer)
|
||||
|
||||
local function NumberLocalizer(props)
|
||||
local number = props.number
|
||||
local render = props.render
|
||||
|
||||
assert(typeof(number) == "number", "prop 'number' must be provided")
|
||||
assert(typeof(render) == "function", "Render prop must be a function")
|
||||
|
||||
return Roact.createElement(LocalizationContextConsumer, {
|
||||
render = function(localizationContext)
|
||||
return render(LocalizationService.formatNumber(localizationContext, number))
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return NumberLocalizer
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local LocalizationService = require(script.Parent.Parent.Parent.Localization.LocalizationService)
|
||||
local LocalizationContextConsumer = require(script.Parent.LocalizationContextConsumer)
|
||||
|
||||
local function TextLocalizer(props)
|
||||
local key = props.key
|
||||
local params = props.params
|
||||
local render = props.render
|
||||
|
||||
assert(typeof(key) == "string", "String key must be provided")
|
||||
assert(typeof(render) == "function", "Render prop must be a function")
|
||||
|
||||
return Roact.createElement(LocalizationContextConsumer, {
|
||||
render = function(localizationContext)
|
||||
return render(LocalizationService.getString(localizationContext, key, params))
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return TextLocalizer
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
--[[
|
||||
Helper for supplying the current Roblox Locale to the Roact
|
||||
tree via context using the LocalizationContextProvider
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
local LocalizationService = game:GetService("LocalizationService")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local LocalizationContextProvider = require(script.Parent.LocalizationContextProvider)
|
||||
|
||||
local getLocalizationContext = require(script.Parent.Parent.Parent.Localization.getLocalizationContext)
|
||||
|
||||
local function provideRobloxLocale(renderFunc)
|
||||
return Roact.createElement(LocalizationContextProvider, {
|
||||
localizationContext = getLocalizationContext(LocalizationService.RobloxLocaleId),
|
||||
render = renderFunc
|
||||
})
|
||||
end
|
||||
|
||||
return provideRobloxLocale
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
--[[
|
||||
Helpful wrapper around LayoutValuesConsumer to make it a
|
||||
little less verbose to use
|
||||
]]
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Roact = require(CorePackages.Roact)
|
||||
|
||||
local LayoutValuesConsumer = require(script.Parent.LayoutValuesConsumer)
|
||||
|
||||
local function withLayoutValues(renderFunc)
|
||||
return Roact.createElement(LayoutValuesConsumer, {
|
||||
render = renderFunc,
|
||||
})
|
||||
end
|
||||
|
||||
return withLayoutValues
|
||||
Reference in New Issue
Block a user