BREAKING CHANGES:
- New versioning system: Allowing any amount of number segments, with prerelease support.
- Any number of segments is supported: 1, 1.0, 1.0.0, 1.0.0.0, ...
- Prerelease labels are compared "digit-run", similar to Debian.
- Plugins must specify a version.
- User-facing plugins should use CalVer. API plugins should use SemVer.
Revenge APIs use SemVer while the new `discord` dependency parses the Discord version string directly.
- Dependency is now a Map, with support for version ranges and optional. Suggested URL is removed. (See new repo system)
- Plugins will now have to declare a dependency on `revenge.api` (Revenge API version) and `discord` (Discord version).
- Manifest now requires a format version (currently `1`)
New APIs:
- lib/plugins/utils: Utilities to format versioning
Features:
- New repo system: Repository design is inspired by Linux package repositories.
- Repos host manifest, versions, channels, download URL/size, and hash for multiple plugins.
- New dependency system: Plugins are versioned, and shouldn't break when updates come.
Plugins can now declare dependency on supported Discord/Revenge API versions, so they won't break with auto-updates.
Dependencies can be optional, but dependency on `revenge.api` and `discord` must be required.
Dependents are soft-disabled when dependencies don't satisfy. Once satisfied, the plugin can start again.
- All updates for running plugins REQUIRE a reload to prevent stale linking issues. Both native and JS-side.
- Update checking is handled entirely by JS. But the native-side still handles installation, indexing, and verification.
- Local indexes are updated against remote indexes. Dependency checking always uses local indexes.
- Users can add custom repositories and custom their priority order. URL is the identity.
- Plugins can now have custom data URI icons instead of being restricted to React Native app assets.
- External plugin installs require UI confirmation before installing.
- Pending Update and Pending Reload filters in Plugins page.
- Ability to browse external plugins in repositories. Official repository will be added soon.
Fixes/Refactor:
- Refactored Plugin-related settings to a separate "Plugin Settings" plugin.
- Masonry layout fixes in landscape.
- Updated plugins now show "reload to apply" toast instead.
- Removed dead code.
109 lines
2.8 KiB
TypeScript
109 lines
2.8 KiB
TypeScript
import { Design } from '@revenge-mod/discord/design'
|
|
import { createContext, useContext, useRef, useState } from 'react'
|
|
import { useClickOutside } from 'react-native-click-outside'
|
|
import type { RefObject } from 'react'
|
|
import type { View } from 'react-native'
|
|
|
|
const { useTooltip } = Design
|
|
|
|
interface TooltipContextValue {
|
|
targetRef: RefObject<View | null>
|
|
setVisible: (visible: boolean) => void
|
|
}
|
|
|
|
const EnablePluginTooltipContext = createContext<TooltipContextValue | null>(
|
|
null,
|
|
)
|
|
const EssentialPluginTooltipContext = createContext<TooltipContextValue | null>(
|
|
null,
|
|
)
|
|
|
|
export function EnablePluginTooltipProvider({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode
|
|
}) {
|
|
const [visible, setVisible] = useState(false)
|
|
const targetRef = useRef<View | null>(null)
|
|
|
|
useTooltip(targetRef, {
|
|
label: 'Plugin must be enabled first',
|
|
position: 'top',
|
|
visible,
|
|
})
|
|
|
|
return (
|
|
<EnablePluginTooltipContext.Provider value={{ targetRef, setVisible }}>
|
|
{children}
|
|
</EnablePluginTooltipContext.Provider>
|
|
)
|
|
}
|
|
|
|
export function EssentialPluginTooltipProvider({
|
|
children,
|
|
}: {
|
|
children: React.ReactNode
|
|
}) {
|
|
const [visible, setVisible] = useState(false)
|
|
const targetRef = useRef<View | null>(null)
|
|
|
|
useTooltip(targetRef, {
|
|
label: 'Plugin needed for Revenge to function properly',
|
|
position: 'top',
|
|
visible,
|
|
})
|
|
|
|
return (
|
|
<EssentialPluginTooltipContext.Provider
|
|
value={{ targetRef, setVisible }}
|
|
>
|
|
{children}
|
|
</EssentialPluginTooltipContext.Provider>
|
|
)
|
|
}
|
|
|
|
export function useEnablePluginTooltip() {
|
|
const context = useContext(EnablePluginTooltipContext)
|
|
if (!context) {
|
|
throw new Error(
|
|
'useEnablePluginTooltip must be used within EnablePluginTooltipProvider',
|
|
)
|
|
}
|
|
return context
|
|
}
|
|
|
|
export function useEssentialPluginTooltip() {
|
|
const context = useContext(EssentialPluginTooltipContext)
|
|
if (!context) {
|
|
throw new Error(
|
|
'useEssentialPluginTooltip must be used within EssentialPluginTooltipProvider',
|
|
)
|
|
}
|
|
return context
|
|
}
|
|
|
|
export function useResetTooltips() {
|
|
const enableTooltip = useContext(EnablePluginTooltipContext)
|
|
const essentialTooltip = useContext(EssentialPluginTooltipContext)
|
|
|
|
return () => {
|
|
enableTooltip?.setVisible(false)
|
|
essentialTooltip?.setVisible(false)
|
|
}
|
|
}
|
|
|
|
export function useClickOutsideTooltip(
|
|
contextHook: () => TooltipContextValue,
|
|
onClickOutside: () => void,
|
|
) {
|
|
const { targetRef, setVisible } = contextHook()
|
|
|
|
const ref = useClickOutside<View>(() => {
|
|
setVisible(false)
|
|
if (targetRef.current === ref.current) {
|
|
onClickOutside()
|
|
}
|
|
})
|
|
|
|
return ref
|
|
}
|