add gs
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
stds.roblox = {
|
||||
read_globals = {
|
||||
game = {
|
||||
other_fields = true,
|
||||
},
|
||||
|
||||
-- Roblox globals
|
||||
"script",
|
||||
|
||||
-- Extra functions
|
||||
"tick", "warn", "spawn", "delay",
|
||||
"wait", "settings", "UserSettings", "typeof",
|
||||
|
||||
-- Types
|
||||
"Vector2", "Vector3",
|
||||
"Color3",
|
||||
"UDim", "UDim2",
|
||||
"Ray",
|
||||
"Rect",
|
||||
"CFrame",
|
||||
"Enum",
|
||||
"Instance",
|
||||
"TweenInfo",
|
||||
"Random",
|
||||
"NumberRange",
|
||||
"NumberSequence",
|
||||
"NumberSequenceKeypoint",
|
||||
"ColorSequence",
|
||||
"BrickColor",
|
||||
}
|
||||
}
|
||||
|
||||
stds.testez = {
|
||||
read_globals = {
|
||||
"describe",
|
||||
"it", "itFOCUS", "itSKIP",
|
||||
"FOCUS", "SKIP", "HACK_NO_XPCALL",
|
||||
"expect",
|
||||
}
|
||||
}
|
||||
|
||||
ignore = {
|
||||
"212", -- unused arguments
|
||||
"421", -- shadowing local variable
|
||||
"422", -- shadowing argument
|
||||
"431", -- shadowing upvalue
|
||||
"432", -- shadowing upvalue argument
|
||||
}
|
||||
|
||||
std = "lua51+roblox"
|
||||
|
||||
files["**/*.spec.lua"] = {
|
||||
std = "+testez",
|
||||
ignore = { "631" }, --Line is too long
|
||||
}
|
||||
|
||||
files["**/*Locale.lua"] = {
|
||||
ignore = { "631" }, --Line is too long
|
||||
}
|
||||
|
||||
files["**/Locales/*.lua"] = {
|
||||
ignore = { "631" }, --Line is too long
|
||||
}
|
||||
|
||||
files["**/Legacy/AvatarEditor/*.lua"] = {
|
||||
ignore = { "121", "122", "211", "213", "612", "614", "631", }, -- Bunch of warnings for legacy code
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local CorePackages = game:GetService("CorePackages")
|
||||
|
||||
local Modules = CoreGui.RobloxGui.Modules
|
||||
|
||||
local FlagSettings = require(Modules.LuaApp.FlagSettings)
|
||||
-- Update LuaApp.FlagSettings using the fact that this script is loaded.
|
||||
FlagSettings:SetIsLuaAppStarterScriptEnabled(true)
|
||||
|
||||
local Roact = require(Modules.Common.Roact)
|
||||
local App = require(Modules.LuaApp.Components.App)
|
||||
local LuaErrorReporter = require(Modules.Common.LuaErrorReporter)
|
||||
|
||||
if not UserSettings().GameSettings:InStudioMode() then
|
||||
-- listen and report errors
|
||||
local errorReporter = LuaErrorReporter.new()
|
||||
errorReporter:setCurrentApp("Mobile")
|
||||
errorReporter:startQueueTimers()
|
||||
end
|
||||
|
||||
-- Common Setup
|
||||
if game.Players.LocalPlayer == nil then
|
||||
game.Players.PlayerAdded:Wait()
|
||||
end
|
||||
|
||||
-- Reduce render quality to optimize performance
|
||||
local renderSteppedConnection = nil
|
||||
renderSteppedConnection = game:GetService("RunService").RenderStepped:connect(function()
|
||||
if renderSteppedConnection then
|
||||
renderSteppedConnection:Disconnect()
|
||||
end
|
||||
settings().Rendering.QualityLevel = 1
|
||||
end)
|
||||
|
||||
local root = Roact.createElement(App)
|
||||
Roact.mount(root, CoreGui, "App")
|
||||
|
||||
-- Run tests when shift+alt+ctrl+T is pressed
|
||||
UserInputService.InputEnded:connect(function(input, gameProcessed)
|
||||
if input.UserInputType == Enum.UserInputType.Keyboard and
|
||||
input.KeyCode == Enum.KeyCode.T and
|
||||
UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) and
|
||||
UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) and
|
||||
UserInputService:IsKeyDown(Enum.KeyCode.LeftAlt)
|
||||
then
|
||||
local TestEZ = require(CorePackages.TestEZ)
|
||||
|
||||
TestEZ.run(Modules.LuaApp, function(results)
|
||||
TestEZ.Reporters.TextReporter.report(results)
|
||||
end)
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,20 @@
|
||||
local scriptContext = game:GetService("ScriptContext")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local RobloxGui = game:GetService("CoreGui"):FindFirstChild("RobloxGui")
|
||||
|
||||
scriptContext:AddCoreScriptLocal("LuaAppStarterScript", RobloxGui)
|
||||
|
||||
local TestLuaMobileApp = require(RobloxGui.Modules.RhodiumTest.Testcase.LuaApp.TestLuaMobileApp)
|
||||
|
||||
-- Run Rhodium test when ctrl+shift+alt+R is pressed
|
||||
UserInputService.InputEnded:connect(function(input, gameProcessed)
|
||||
if input.UserInputType == Enum.UserInputType.Keyboard and
|
||||
UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) and
|
||||
UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) and
|
||||
UserInputService:IsKeyDown(Enum.KeyCode.LeftAlt)
|
||||
then
|
||||
if input.KeyCode == Enum.KeyCode.R then
|
||||
TestLuaMobileApp()
|
||||
end
|
||||
end
|
||||
end)
|
||||
@@ -0,0 +1,398 @@
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
|
||||
local Modules = CoreGui.RobloxGui.Modules
|
||||
|
||||
local Analytics = require(Modules.Common.Analytics)
|
||||
local LuaErrorReporter = require(Modules.Common.LuaErrorReporter)
|
||||
local Create = require(Modules.Mobile.Create)
|
||||
local Constants = require(Modules.Mobile.Constants)
|
||||
local MobileAppState = require(Modules.Mobile.AppState)
|
||||
local AvatarEditorFlags = require(Modules.LuaApp.Legacy.AvatarEditor.Flags)
|
||||
local AppGui = require(Modules.LuaApp.Legacy.AvatarEditor.AppGui)
|
||||
local getScreenBottomInset = require(Modules.LuaApp.getScreenBottomInset)
|
||||
local NotificationType = require(Modules.LuaApp.Enum.NotificationType)
|
||||
|
||||
local RefactoringAvatarEditorSetup = AvatarEditorFlags:GetFlag("RefactoringAvatarEditorSetup")
|
||||
local luaAppLegacyInputDisabledGlobally = settings():GetFFlag('LuaAppLegacyInputDisabledGlobally2')
|
||||
local EnableLuaEventStreamRelease = settings():GetFFlag('EnableLuaEventStreamRelease')
|
||||
|
||||
local ChatMaster = nil
|
||||
local AvatarEditorMain = nil
|
||||
|
||||
|
||||
local function reportAppReady(analyticsImpl, context)
|
||||
analyticsImpl.EventStream:setRBXEventStream("appReady", context)
|
||||
end
|
||||
|
||||
local function notifyAppReady(appName)
|
||||
spawn(function()
|
||||
GuiService:BroadcastNotification(appName, NotificationType.APP_READY)
|
||||
end)
|
||||
local analyticsImpl = Analytics.new()
|
||||
reportAppReady(analyticsImpl, appName)
|
||||
end
|
||||
|
||||
local AvatarEditorSetup = nil
|
||||
local AppNameEnum = {}
|
||||
if RefactoringAvatarEditorSetup then
|
||||
AvatarEditorSetup = require(Modules.Mobile.AvatarEditorSetup)
|
||||
AppNameEnum = require(Modules.Mobile.AppNameEnum)
|
||||
else
|
||||
local AppNames = {
|
||||
"AvatarEditor",
|
||||
"Chat",
|
||||
"ShareGameToChat",
|
||||
}
|
||||
|
||||
for i = 1, #AppNames do
|
||||
AppNameEnum[AppNames[i]] = AppNames[i]
|
||||
end
|
||||
|
||||
setmetatable(AppNameEnum, {
|
||||
__index = function(self, key)
|
||||
error(("Invalid AppNameEnum %q"):format(tostring(key)))
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
--This is to cover the sky while loading, and also prevent the sky from flashing in when the global gui inset changes
|
||||
local screenGui
|
||||
|
||||
if RefactoringAvatarEditorSetup then
|
||||
AvatarEditorSetup:Initialize(notifyAppReady)
|
||||
else
|
||||
|
||||
if not UserSettings().GameSettings:InStudioMode() then
|
||||
screenGui = Create.new "ScreenGui" {
|
||||
Name = "SkyCoverGui",
|
||||
DisplayOrder = 1,
|
||||
|
||||
Create.new "Frame" {
|
||||
Name = "HackHeader",
|
||||
Position = UDim2.new(0, 0, 0, 0),
|
||||
Size = UDim2.new(1, 0, 0, UserInputService.NavBarSize.Y+UserInputService.StatusBarSize.Y),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Constants.Color.BLUE_PRESSED,
|
||||
},
|
||||
Create.new "Frame" {
|
||||
Name = "HackBody",
|
||||
Position = UDim2.new(0, 0, 0, UserInputService.NavBarSize.Y+UserInputService.StatusBarSize.Y),
|
||||
Size = UDim2.new(1, 0, 1, 200),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Constants.Color.WHITE,
|
||||
},
|
||||
}
|
||||
else
|
||||
screenGui = Create.new "ScreenGui" {
|
||||
Name = "SkyCoverGui",
|
||||
DisplayOrder = 1,
|
||||
|
||||
Create.new "Frame" {
|
||||
Name = "HackHeader",
|
||||
Position = UDim2.new(0, 0, 0, 0),
|
||||
Size = UDim2.new(1, 0, 0, 64),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Constants.Color.BLUE_PRESSED,
|
||||
},
|
||||
Create.new "Frame" {
|
||||
Name = "HackBody",
|
||||
Position = UDim2.new(0, 0, 0, 64),
|
||||
Size = UDim2.new(1, 0, 1, 200),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Constants.Color.WHITE,
|
||||
},
|
||||
}
|
||||
end
|
||||
local function adjustScreenGuiLayout()
|
||||
local headerHeight = UserInputService.NavBarSize.Y+UserInputService.StatusBarSize.Y
|
||||
screenGui.HackHeader.Size = UDim2.new(1, 0, 0, headerHeight)
|
||||
screenGui.HackBody.Position = UDim2.new(0, 0, 0, headerHeight)
|
||||
end
|
||||
local navBarChanged = UserInputService:GetPropertyChangedSignal("NavBarSize")
|
||||
navBarChanged:Connect(function()
|
||||
adjustScreenGuiLayout()
|
||||
end)
|
||||
local statusBarChanged = UserInputService:GetPropertyChangedSignal("StatusBarSize")
|
||||
statusBarChanged:Connect(function()
|
||||
adjustScreenGuiLayout()
|
||||
end)
|
||||
|
||||
screenGui.Parent = CoreGui
|
||||
|
||||
--[[
|
||||
As long as initializing AvatarEditorMain requires a yield, it has to run in a
|
||||
spawned task. It is then possible for the user to switch apps in the middle of
|
||||
initialization. So, openAvatarEditor and closeAvatarEditor first check to see
|
||||
if it's currently initializing, and if it is, they set a bool indicating whether
|
||||
to call Start() when initialization is done.
|
||||
]]
|
||||
local startAvatarEditorAfterInitializing = false
|
||||
|
||||
end
|
||||
|
||||
local function openChat()
|
||||
if ChatMaster == nil then
|
||||
ChatMaster = require(Modules.ChatMaster).new()
|
||||
end
|
||||
|
||||
ChatMaster:Start()
|
||||
notifyAppReady(AppNameEnum.Chat)
|
||||
end
|
||||
|
||||
|
||||
local function closeChat()
|
||||
ChatMaster:Stop()
|
||||
end
|
||||
|
||||
local function openShareGameToChat(parameters)
|
||||
if ChatMaster == nil then
|
||||
ChatMaster = require(Modules.ChatMaster).new()
|
||||
end
|
||||
|
||||
ChatMaster:Start(ChatMaster.Type.GameShare, parameters)
|
||||
notifyAppReady(AppNameEnum.ShareGameToChat)
|
||||
end
|
||||
|
||||
|
||||
local function closeShareGameToChat()
|
||||
ChatMaster:Stop(ChatMaster.Type.GameShare)
|
||||
end
|
||||
|
||||
|
||||
local openAvatarEditor
|
||||
if not RefactoringAvatarEditorSetup then
|
||||
openAvatarEditor = function()
|
||||
startAvatarEditorAfterInitializing = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local closeAvatarEditor
|
||||
if not RefactoringAvatarEditorSetup then
|
||||
closeAvatarEditor = function()
|
||||
startAvatarEditorAfterInitializing = false
|
||||
end
|
||||
end
|
||||
|
||||
if not RefactoringAvatarEditorSetup then
|
||||
|
||||
local function avatarEditorInitialization()
|
||||
spawn(function()
|
||||
|
||||
local header
|
||||
local appGui
|
||||
|
||||
if not UserSettings().GameSettings:InStudioMode() then
|
||||
header = require(Modules.LuaApp.Legacy.AvatarEditor.Header).new("Avatar",
|
||||
UserInputService.NavBarSize.Y, UserInputService.StatusBarSize.Y)
|
||||
|
||||
local headerHeight = UserInputService.StatusBarSize.Y + UserInputService.NavBarSize.Y
|
||||
appGui = AppGui(
|
||||
UDim2.new(0, 0, 0, headerHeight),
|
||||
UDim2.new(1, 0, 1, -headerHeight))
|
||||
|
||||
local function updateUIDimensions()
|
||||
header:SetNavAndStatusBarHeight(UserInputService.NavBarSize.Y, UserInputService.StatusBarSize.Y)
|
||||
local headerHeight = UserInputService.NavBarSize.Y + UserInputService.StatusBarSize.Y
|
||||
appGui:setDimensions(
|
||||
UDim2.new(0, 0, 0, headerHeight),
|
||||
UDim2.new(1, 0, 1, -headerHeight))
|
||||
end
|
||||
|
||||
UserInputService:GetPropertyChangedSignal("NavBarSize"):Connect( updateUIDimensions )
|
||||
UserInputService:GetPropertyChangedSignal("StatusBarSize"):Connect( updateUIDimensions )
|
||||
else
|
||||
local navBarHeight = 44
|
||||
local statusBarHeight = 20
|
||||
|
||||
header = require(Modules.LuaApp.Legacy.AvatarEditor.Header).new("Avatar",
|
||||
navBarHeight, statusBarHeight)
|
||||
|
||||
local headerHeight = navBarHeight + statusBarHeight
|
||||
appGui = AppGui(
|
||||
UDim2.new(0, 0, 0, headerHeight),
|
||||
UDim2.new(1, 0, 1, -headerHeight))
|
||||
end
|
||||
|
||||
header.rbx.Parent = appGui.ScreenGui
|
||||
|
||||
AvatarEditorMain =
|
||||
require(Modules.LuaApp.Legacy.AvatarEditor.AvatarEditorMain)
|
||||
.new(appGui)
|
||||
|
||||
local function startAvatarEditor()
|
||||
screenGui.HackBody.Visible = false
|
||||
AvatarEditorMain:Start()
|
||||
notifyAppReady(AppNameEnum.AvatarEditor)
|
||||
end
|
||||
|
||||
if startAvatarEditorAfterInitializing then
|
||||
startAvatarEditor()
|
||||
end
|
||||
|
||||
openAvatarEditor = startAvatarEditor
|
||||
|
||||
closeAvatarEditor = function()
|
||||
screenGui.HackBody.Visible = true
|
||||
AvatarEditorMain:Stop()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local hasRunInitialization = false
|
||||
local renderSteppedConnection = nil
|
||||
renderSteppedConnection = game:GetService("RunService").RenderStepped:connect(function()
|
||||
if not hasRunInitialization then
|
||||
hasRunInitialization = true
|
||||
if renderSteppedConnection then
|
||||
renderSteppedConnection:Disconnect()
|
||||
end
|
||||
avatarEditorInitialization()
|
||||
end
|
||||
end)
|
||||
|
||||
end
|
||||
|
||||
local function installStudioTestingHooks(store)
|
||||
local ActionType = require(CoreGui.RobloxGui.Modules.Mobile.ActionType)
|
||||
print("Testing in Studio")
|
||||
print("")
|
||||
print("Use number keys:")
|
||||
print("1: AvatarEditor")
|
||||
print("2: Chat")
|
||||
print("")
|
||||
|
||||
local function onKeyPress(inputObject, gameProcessedEvent)
|
||||
local actionMap = {
|
||||
[Enum.KeyCode.One] = function()
|
||||
store:Dispatch( {type = ActionType.OpenApp, appName = AppNameEnum.AvatarEditor} )
|
||||
end;
|
||||
|
||||
[Enum.KeyCode.Two] = function()
|
||||
store:Dispatch( {type = ActionType.OpenApp, appName = AppNameEnum.Chat} )
|
||||
end;
|
||||
}
|
||||
|
||||
(actionMap[inputObject.KeyCode] or function()end)()
|
||||
end
|
||||
|
||||
UserInputService.InputBegan:connect(onKeyPress)
|
||||
end
|
||||
|
||||
|
||||
local initMobile
|
||||
|
||||
if not UserSettings().GameSettings:InStudioMode()
|
||||
then
|
||||
initMobile = function()
|
||||
local errorReporter = LuaErrorReporter.new()
|
||||
errorReporter:setCurrentApp("Mobile")
|
||||
errorReporter:startQueueTimers()
|
||||
-- to do : observe app lifecycle changes to disable timers when in background
|
||||
|
||||
if EnableLuaEventStreamRelease then
|
||||
game:BindToClose(function()
|
||||
-- there is currently a bug with the EventStream, where the stream is not released
|
||||
-- by the game engine. This call is a temporary work around until a new api is available.
|
||||
local analytics = Analytics.new()
|
||||
analytics.EventStream:releaseRBXEventStream()
|
||||
end)
|
||||
end
|
||||
|
||||
local appState = MobileAppState.new()
|
||||
|
||||
local function setGlobalGuiInset()
|
||||
GuiService:SetGlobalGuiInset(0, 0, 0, getScreenBottomInset())
|
||||
end
|
||||
|
||||
setGlobalGuiInset()
|
||||
|
||||
UserInputService:GetPropertyChangedSignal("BottomBarSize"):Connect(setGlobalGuiInset)
|
||||
|
||||
GuiService.SafeZoneOffsetsChanged:Connect(setGlobalGuiInset)
|
||||
|
||||
UserInputService.LegacyInputEventsEnabled = (not luaAppLegacyInputDisabledGlobally)
|
||||
|
||||
appState.store.changed:connect(
|
||||
function(newState, oldState)
|
||||
if oldState.OpenApp ~= newState.OpenApp then
|
||||
if newState.OpenApp == AppNameEnum.Chat then
|
||||
openChat()
|
||||
end
|
||||
|
||||
if newState.OpenApp == AppNameEnum.AvatarEditor then
|
||||
if RefactoringAvatarEditorSetup then
|
||||
AvatarEditorSetup:Open()
|
||||
else
|
||||
openAvatarEditor()
|
||||
end
|
||||
end
|
||||
|
||||
if newState.OpenApp == AppNameEnum.ShareGameToChat then
|
||||
openShareGameToChat(newState.Parameters)
|
||||
end
|
||||
|
||||
if oldState.OpenApp == AppNameEnum.Chat then
|
||||
closeChat()
|
||||
end
|
||||
|
||||
if oldState.OpenApp == AppNameEnum.AvatarEditor then
|
||||
if RefactoringAvatarEditorSetup then
|
||||
AvatarEditorSetup:Close()
|
||||
else
|
||||
closeAvatarEditor()
|
||||
end
|
||||
end
|
||||
|
||||
if oldState.OpenApp == AppNameEnum.ShareGameToChat then
|
||||
closeShareGameToChat()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
)
|
||||
end
|
||||
else
|
||||
initMobile = function()
|
||||
local appState = MobileAppState.new()
|
||||
|
||||
GuiService:SetGlobalGuiInset(0, 0, 0, 49)
|
||||
|
||||
appState.store.changed:connect(
|
||||
function(newState, oldState)
|
||||
if oldState.OpenApp ~= newState.OpenApp then
|
||||
if newState.OpenApp == AppNameEnum.Chat then
|
||||
--openChat()
|
||||
end
|
||||
|
||||
if newState.OpenApp == AppNameEnum.AvatarEditor then
|
||||
if RefactoringAvatarEditorSetup then
|
||||
AvatarEditorSetup:Open()
|
||||
else
|
||||
openAvatarEditor()
|
||||
end
|
||||
end
|
||||
|
||||
if oldState.OpenApp == AppNameEnum.Chat then
|
||||
--closeChat()
|
||||
end
|
||||
|
||||
if oldState.OpenApp == AppNameEnum.AvatarEditor then
|
||||
if RefactoringAvatarEditorSetup then
|
||||
AvatarEditorSetup:Close()
|
||||
else
|
||||
closeAvatarEditor()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
installStudioTestingHooks(appState.store)
|
||||
end
|
||||
end
|
||||
|
||||
initMobile()
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
|
||||
local scriptContext = game:GetService("ScriptContext")
|
||||
local RobloxGui = game:GetService("CoreGui"):FindFirstChild("RobloxGui")
|
||||
|
||||
scriptContext:AddCoreScriptLocal("MobileMaster", RobloxGui)
|
||||
@@ -0,0 +1,16 @@
|
||||
local ActionTypeNames = {
|
||||
"OpenApp",
|
||||
}
|
||||
|
||||
local ActionType = {}
|
||||
for i = 1, #ActionTypeNames do
|
||||
ActionType[ActionTypeNames[i]] = ActionTypeNames[i]
|
||||
end
|
||||
|
||||
setmetatable(ActionType, {
|
||||
__index = function(self, key)
|
||||
error(("Invalid ActionType %q"):format(tostring(key)))
|
||||
end
|
||||
})
|
||||
|
||||
return ActionType
|
||||
@@ -0,0 +1,18 @@
|
||||
local AppNames = {
|
||||
"AvatarEditor",
|
||||
"Chat",
|
||||
"ShareGameToChat",
|
||||
}
|
||||
|
||||
local AppNameEnum = {}
|
||||
for i = 1, #AppNames do
|
||||
AppNameEnum[AppNames[i]] = AppNames[i]
|
||||
end
|
||||
|
||||
setmetatable(AppNameEnum, {
|
||||
__index = function(self, key)
|
||||
error(("Invalid AppNameEnum %q"):format(tostring(key)))
|
||||
end
|
||||
})
|
||||
|
||||
return AppNameEnum
|
||||
@@ -0,0 +1,14 @@
|
||||
local Modules = script.Parent.Parent
|
||||
local Immutable = require(Modules.Common.Immutable)
|
||||
|
||||
return function(state, action)
|
||||
state = state or {OpenApp = "", Paramters = {}}
|
||||
|
||||
if action.type == "OpenApp" then
|
||||
state = Immutable.Set(state, "OpenApp", action.appName)
|
||||
state = Immutable.Set(state, "Parameters", action.parameters)
|
||||
end
|
||||
|
||||
return state
|
||||
end
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
local Modules = script.Parent.Parent
|
||||
|
||||
local AppReducer = require(Modules.Mobile.AppReducer)
|
||||
local Store = require(Modules.Common.Rodux).Store
|
||||
local NavigationEventReceiver = require(Modules.Mobile.NavigationEventReceiver)
|
||||
|
||||
local AppState = {}
|
||||
|
||||
function AppState.new()
|
||||
local state = {}
|
||||
|
||||
state.store = Store.new(AppReducer)
|
||||
|
||||
state.NavigationEventReceiver = NavigationEventReceiver:init(state)
|
||||
|
||||
return state
|
||||
end
|
||||
|
||||
function AppState:Destruct()
|
||||
self.store:Destruct()
|
||||
end
|
||||
|
||||
return AppState
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
local CoreGui = game:GetService("CoreGui")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local RunService = game:GetService("RunService")
|
||||
|
||||
local Modules = CoreGui.RobloxGui.Modules
|
||||
|
||||
local AppNameEnum = require(Modules.Mobile.AppNameEnum)
|
||||
local Create = require(Modules.Mobile.Create)
|
||||
local Constants = require(Modules.Mobile.Constants)
|
||||
local AppGui = require(Modules.LuaApp.Legacy.AvatarEditor.AppGui)
|
||||
|
||||
local LuaAppConstants = require(Modules.LuaApp.Constants)
|
||||
|
||||
local AvatarEditorSetup = {}
|
||||
|
||||
function AvatarEditorSetup:Initialize(notifyAppReady, useRoactLuaApp)
|
||||
--This is to cover the sky while loading, and also prevent the sky from flashing in when the global gui inset changes
|
||||
local screenGui
|
||||
|
||||
if not UserSettings().GameSettings:InStudioMode() then
|
||||
screenGui = Create.new "ScreenGui" {
|
||||
Name = "SkyCoverGui",
|
||||
DisplayOrder = 1,
|
||||
|
||||
Create.new "Frame" {
|
||||
Name = "HackHeader",
|
||||
Position = UDim2.new(0, 0, 0, 0),
|
||||
Size = UDim2.new(1, 0, 0, UserInputService.NavBarSize.Y+UserInputService.StatusBarSize.Y),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Constants.Color.BLUE_PRESSED,
|
||||
},
|
||||
Create.new "Frame" {
|
||||
Name = "HackBody",
|
||||
Position = UDim2.new(0, 0, 0, UserInputService.NavBarSize.Y+UserInputService.StatusBarSize.Y),
|
||||
Size = UDim2.new(1, 0, 1, 200),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Constants.Color.WHITE,
|
||||
},
|
||||
}
|
||||
else
|
||||
screenGui = Create.new "ScreenGui" {
|
||||
Name = "SkyCoverGui",
|
||||
DisplayOrder = 1,
|
||||
|
||||
Create.new "Frame" {
|
||||
Name = "HackHeader",
|
||||
Position = UDim2.new(0, 0, 0, 0),
|
||||
Size = UDim2.new(1, 0, 0, 64),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Constants.Color.BLUE_PRESSED,
|
||||
},
|
||||
Create.new "Frame" {
|
||||
Name = "HackBody",
|
||||
Position = UDim2.new(0, 0, 0, 64),
|
||||
Size = UDim2.new(1, 0, 1, 200),
|
||||
BorderSizePixel = 0,
|
||||
BackgroundColor3 = Constants.Color.WHITE,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
local function adjustScreenGuiLayout()
|
||||
local headerHeight = UserInputService.NavBarSize.Y+UserInputService.StatusBarSize.Y
|
||||
screenGui.HackHeader.Size = UDim2.new(1, 0, 0, headerHeight)
|
||||
screenGui.HackBody.Position = UDim2.new(0, 0, 0, headerHeight)
|
||||
end
|
||||
|
||||
local navBarChanged = UserInputService:GetPropertyChangedSignal("NavBarSize")
|
||||
navBarChanged:Connect(function()
|
||||
adjustScreenGuiLayout()
|
||||
end)
|
||||
|
||||
local statusBarChanged = UserInputService:GetPropertyChangedSignal("StatusBarSize")
|
||||
statusBarChanged:Connect(function()
|
||||
adjustScreenGuiLayout()
|
||||
end)
|
||||
|
||||
screenGui.Parent = CoreGui
|
||||
|
||||
if useRoactLuaApp then
|
||||
screenGui.Enabled = false
|
||||
end
|
||||
|
||||
--[[
|
||||
As long as initializing AvatarEditorMain requires a yield, it has to run in a
|
||||
spawned task. It is then possible for the user to switch apps in the middle of
|
||||
initialization. So, openAvatarEditor and closeAvatarEditor first check to see
|
||||
if it's currently initializing, and if it is, they set a bool indicating whether
|
||||
to call Start() when initialization is done.
|
||||
]]
|
||||
local startAvatarEditorAfterInitializing = false
|
||||
|
||||
self.openAvatarEditor = function()
|
||||
startAvatarEditorAfterInitializing = true
|
||||
end
|
||||
|
||||
self.closeAvatarEditor = function()
|
||||
startAvatarEditorAfterInitializing = false
|
||||
end
|
||||
|
||||
local function avatarEditorInitialization()
|
||||
spawn(function()
|
||||
self.AppGui = nil
|
||||
|
||||
if not useRoactLuaApp then
|
||||
local header
|
||||
if not UserSettings().GameSettings:InStudioMode() then
|
||||
header = require(Modules.LuaApp.Legacy.AvatarEditor.Header).new("Avatar",
|
||||
UserInputService.NavBarSize.Y, UserInputService.StatusBarSize.Y)
|
||||
|
||||
local headerHeight = UserInputService.StatusBarSize.Y + UserInputService.NavBarSize.Y
|
||||
self.AppGui = AppGui(
|
||||
UDim2.new(0, 0, 0, headerHeight),
|
||||
UDim2.new(1, 0, 1, -headerHeight))
|
||||
|
||||
local function updateUIDimensions()
|
||||
header:SetNavAndStatusBarHeight(UserInputService.NavBarSize.Y, UserInputService.StatusBarSize.Y)
|
||||
local headerHeight = UserInputService.NavBarSize.Y + UserInputService.StatusBarSize.Y
|
||||
self:UpdateTopBarHeight(headerHeight)
|
||||
end
|
||||
|
||||
UserInputService:GetPropertyChangedSignal("NavBarSize"):Connect( updateUIDimensions )
|
||||
UserInputService:GetPropertyChangedSignal("StatusBarSize"):Connect( updateUIDimensions )
|
||||
else
|
||||
local navBarHeight = 44
|
||||
local statusBarHeight = 20
|
||||
|
||||
header = require(Modules.LuaApp.Legacy.AvatarEditor.Header).new("Avatar",
|
||||
navBarHeight, statusBarHeight)
|
||||
|
||||
local headerHeight = navBarHeight + statusBarHeight
|
||||
self.AppGui = AppGui(
|
||||
UDim2.new(0, 0, 0, headerHeight),
|
||||
UDim2.new(1, 0, 1, -headerHeight))
|
||||
end
|
||||
header.rbx.Parent = self.AppGui.ScreenGui
|
||||
else
|
||||
-- Sync with default value in LuaApp topbar reducer
|
||||
local topBarHeight = LuaAppConstants.TOP_BAR_SIZE
|
||||
self.AppGui = AppGui(
|
||||
UDim2.new(0, 0, 0, topBarHeight),
|
||||
UDim2.new(1, 0, 1, -topBarHeight))
|
||||
end
|
||||
|
||||
AvatarEditorMain =
|
||||
require(Modules.LuaApp.Legacy.AvatarEditor.AvatarEditorMain)
|
||||
.new(self.AppGui)
|
||||
|
||||
local function startAvatarEditor()
|
||||
if useRoactLuaApp then
|
||||
screenGui.Enabled = true
|
||||
end
|
||||
screenGui.HackBody.Visible = false
|
||||
AvatarEditorMain:Start()
|
||||
|
||||
-- Staging broadcasting of APP_READY to accomodate for unpredictable
|
||||
-- delay on the native side.
|
||||
-- Once Lua tab bar is integrated, there will be no use for this
|
||||
notifyAppReady(AppNameEnum.AvatarEditor)
|
||||
end
|
||||
|
||||
if startAvatarEditorAfterInitializing then
|
||||
startAvatarEditor()
|
||||
end
|
||||
|
||||
self.openAvatarEditor = startAvatarEditor
|
||||
|
||||
self.closeAvatarEditor = function()
|
||||
screenGui.HackBody.Visible = true
|
||||
AvatarEditorMain:Stop()
|
||||
if useRoactLuaApp then
|
||||
screenGui.Enabled = false
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local hasRunInitialization = false
|
||||
local renderSteppedConnection = nil
|
||||
renderSteppedConnection = RunService.RenderStepped:connect(function()
|
||||
if not hasRunInitialization then
|
||||
hasRunInitialization = true
|
||||
if renderSteppedConnection then
|
||||
renderSteppedConnection:Disconnect()
|
||||
end
|
||||
avatarEditorInitialization()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function AvatarEditorSetup:Open()
|
||||
if not _G.__TESTEZ_RUNNING_TEST__ then
|
||||
RunService:setThrottleFramerateEnabled(false)
|
||||
end
|
||||
self.openAvatarEditor()
|
||||
end
|
||||
|
||||
function AvatarEditorSetup:Close()
|
||||
if not _G.__TESTEZ_RUNNING_TEST__ then
|
||||
RunService:setThrottleFramerateEnabled(true)
|
||||
end
|
||||
self.closeAvatarEditor()
|
||||
end
|
||||
|
||||
function AvatarEditorSetup:UpdateTopBarHeight(topBarHeight)
|
||||
if self.AppGui then
|
||||
self.AppGui:setDimensions(
|
||||
UDim2.new(0, 0, 0, topBarHeight),
|
||||
UDim2.new(1, 0, 1, -topBarHeight))
|
||||
end
|
||||
end
|
||||
|
||||
return AvatarEditorSetup
|
||||
@@ -0,0 +1,70 @@
|
||||
local Constants = {
|
||||
Color = {
|
||||
GRAY1 = Color3.fromRGB(25, 25, 25),
|
||||
GRAY2 = Color3.fromRGB(117, 117, 117),
|
||||
GRAY3 = Color3.fromRGB(184, 184, 184),
|
||||
GRAY4 = Color3.fromRGB(227, 227, 227),
|
||||
GRAY5 = Color3.fromRGB(242, 242, 242),
|
||||
GRAY6 = Color3.fromRGB(245, 245, 245),
|
||||
WHITE = Color3.fromRGB(255, 255, 255),
|
||||
BLUE_PRIMARY = Color3.fromRGB(0, 162, 255),
|
||||
BLUE_HOVER = Color3.fromRGB(50, 181, 255),
|
||||
BLUE_PRESSED = Color3.fromRGB(0, 116, 189),
|
||||
BLUE_DISABLED = Color3.fromRGB(153, 218, 255),
|
||||
GREEN_PRIMARY = Color3.fromRGB(2, 183, 87),
|
||||
GREEN_HOVER = Color3.fromRGB(63, 198, 121),
|
||||
GREEN_PRESSED = Color3.fromRGB(17, 130, 55),
|
||||
GREEN_DISABLED = Color3.fromRGB(163, 226, 189),
|
||||
RED_PRIMARY = Color3.fromRGB(226, 35, 26),
|
||||
RED_NEGATIVE = Color3.fromRGB(216, 104, 104),
|
||||
RED_HOVER = Color3.fromRGB(226, 118, 118),
|
||||
RED_PRESSED = Color3.fromRGB(172, 30, 45),
|
||||
ORANGE_WARNING = Color3.fromRGB(246, 136, 2),
|
||||
ORANGE_FAVORITE = Color3.fromRGB(246, 183, 2),
|
||||
BROWN_TIX = Color3.fromRGB(204, 158, 113),
|
||||
ALPHA_SHADOW_PRIMARY = 0.3, -- Used with Gray1
|
||||
ALPHA_SHADOW_HOVER = 0.75, -- Used with Gray1
|
||||
CONVERSATION_BACKGROUND = Color3.fromRGB(224, 224, 224),
|
||||
},
|
||||
Header = {
|
||||
HEIGHT = 64,
|
||||
},
|
||||
Tween = {
|
||||
PHONE_TWEEN_TIME = 0.25,
|
||||
PHONE_TWEEN_STYLE = Enum.EasingStyle.Quad,
|
||||
PHONE_TWEEN_DIRECTION = Enum.EasingDirection.Out,
|
||||
},
|
||||
PresenceType = {
|
||||
NONE = "NONE",
|
||||
ONLINE = "ONLINE",
|
||||
IN_GAME = "IN_GAME",
|
||||
IN_STUDIO = "IN_STUDIO",
|
||||
},
|
||||
ServerState = {
|
||||
NONE = "NONE",
|
||||
CREATING = "CREATING",
|
||||
CREATED = "CREATED",
|
||||
},
|
||||
ConversationLoadingState = {
|
||||
NONE = "NONE",
|
||||
LOADING = "LOADING",
|
||||
DONE = "DONE"
|
||||
},
|
||||
PresenceColors = {
|
||||
NONE = nil, --Your code will crash if you render this. Intended.
|
||||
ONLINE = Color3.fromRGB(0, 162, 255),
|
||||
IN_GAME = Color3.fromRGB(2, 183, 87),
|
||||
IN_STUDIO = Color3.fromRGB(246, 136, 2),
|
||||
},
|
||||
Text = {
|
||||
INPUT_PLACEHOLDER = Color3.fromRGB(189, 189, 189),
|
||||
INPUT = Color3.fromRGB(25, 25, 25),
|
||||
POST_TYPING_STATUS_INTERVAL = 3, --How frequently do we POST our typing status if we're still typing
|
||||
},
|
||||
MAX_PARTICIPANT_COUNT = 5,
|
||||
MIN_PARTICIPANT_COUNT = 2,
|
||||
-- This value actually comes from iOS, but we are shortcutting actually getting the value from there.
|
||||
TAB_BAR_SIZE = 49,
|
||||
}
|
||||
|
||||
return Constants
|
||||
@@ -0,0 +1,82 @@
|
||||
local Create = {
|
||||
events = {}
|
||||
}
|
||||
|
||||
--[[
|
||||
Merge a list of dictionary tables into one table
|
||||
]]
|
||||
function Create.merge(...)
|
||||
if select("#", ...) == 1 then
|
||||
return (...)
|
||||
end
|
||||
|
||||
local new = {}
|
||||
|
||||
for i = 1, select("#", ...) do
|
||||
for key, value in pairs(select(i, ...)) do
|
||||
-- Push numeric keys as a list
|
||||
if (type(key) == "number") then
|
||||
table.insert(new, value)
|
||||
else
|
||||
new[key] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return new
|
||||
end
|
||||
|
||||
--[[
|
||||
Create a new instance with the given type properties.
|
||||
|
||||
Usage:
|
||||
Create.new "Frame" {
|
||||
Name = "MyFrame"
|
||||
}
|
||||
|
||||
-- OR --
|
||||
|
||||
Create "Frame" {
|
||||
Name = "MyFrame"
|
||||
}
|
||||
|
||||
Makes no assumptions about the types of children added. The only requirement
|
||||
is that the "Parent" property on them can be assigned.
|
||||
]]
|
||||
function Create.new(name)
|
||||
return function(...)
|
||||
local props = Create.merge(...)
|
||||
local new = Instance.new(name)
|
||||
|
||||
-- Add properties to this instance; all string keys are property names
|
||||
for key, value in pairs(props) do
|
||||
if type(key) == "string" then
|
||||
assert(key ~= "Parent", "Don't set 'Parent' using Create!")
|
||||
|
||||
new[key] = value
|
||||
elseif type(key) == "table" then
|
||||
-- Events use a special-case key
|
||||
if key == Create.events then
|
||||
for name, event in pairs(value) do
|
||||
new[name]:connect(event)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Add children after all the properties are set
|
||||
for _, child in ipairs(props) do
|
||||
child.Parent = new
|
||||
end
|
||||
|
||||
return new
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(Create, {
|
||||
__call = function(self, ...)
|
||||
return Create.new(...)
|
||||
end
|
||||
})
|
||||
|
||||
return Create
|
||||
@@ -0,0 +1,33 @@
|
||||
local Modules = script.Parent
|
||||
|
||||
local ActionType = require(Modules.ActionType)
|
||||
|
||||
local NotificationService = game:GetService("NotificationService")
|
||||
local HttpService = game:GetService("HttpService")
|
||||
|
||||
local NavigationEventReceiver = {}
|
||||
|
||||
function NavigationEventReceiver:init(appState)
|
||||
|
||||
local function onNaviationNotifications(eventData)
|
||||
local decodedDetail = HttpService:JSONDecode(eventData.detail)
|
||||
local detailType = decodedDetail.Type or eventData.detailType
|
||||
if detailType == "Destination" then
|
||||
if decodedDetail.appName then
|
||||
appState.store:dispatch( {type = ActionType.OpenApp, appName = decodedDetail.appName, parameters = decodedDetail.parameters} )
|
||||
else
|
||||
appState.store:dispatch( {type = ActionType.OpenApp, appName = eventData.detail, parameters = {}} )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onRobloxEventReceived(eventData)
|
||||
if eventData.namespace == "Navigations" then
|
||||
onNaviationNotifications(eventData)
|
||||
end
|
||||
end
|
||||
|
||||
NotificationService.RobloxEventReceived:connect(onRobloxEventReceived)
|
||||
end
|
||||
|
||||
return NavigationEventReceiver
|
||||
Reference in New Issue
Block a user