mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-03-22 01:34:13 -05:00
Compare commits
143 Commits
master
...
09/13/2025
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
073d8a5169 | ||
|
|
320569e98f | ||
|
|
2820c82182 | ||
|
|
5ef8da359e | ||
|
|
d313ae33af | ||
|
|
046d5581ee | ||
|
|
16e9c88227 | ||
|
|
e7e43a6630 | ||
|
|
c34672f9be | ||
|
|
fd35ea7db9 | ||
|
|
0438937c5c | ||
|
|
781df01d1c | ||
|
|
85dfaa73b9 | ||
|
|
629a0b72dd | ||
|
|
505e640f46 | ||
|
|
42f42dbf79 | ||
|
|
fa5a5e3c19 | ||
|
|
8b72f08dcc | ||
|
|
1095971895 | ||
|
|
700790dba1 | ||
|
|
3af9884627 | ||
|
|
8653e9b033 | ||
|
|
e658545a48 | ||
|
|
e1d592ee9c | ||
|
|
f052d0b2a7 | ||
|
|
5d87012269 | ||
|
|
b78cb23b49 | ||
|
|
c7d5f13ec1 | ||
|
|
90dfb79bb3 | ||
|
|
e95747b954 | ||
|
|
02a9cdb064 | ||
|
|
828050c1b9 | ||
|
|
a072c28dfb | ||
|
|
75303dcebb | ||
|
|
7e52c4728c | ||
|
|
e481601655 | ||
|
|
4f8c149ef5 | ||
|
|
51da0fd72f | ||
|
|
27ff070b7a | ||
|
|
fd469c057d | ||
|
|
6166856b5f | ||
|
|
01a7b8467d | ||
|
|
68fcf79cf5 | ||
|
|
bb26eb98ec | ||
|
|
3b52b82e38 | ||
|
|
e394bdbbf3 | ||
|
|
babfcebfa5 | ||
|
|
2bb57ccb43 | ||
|
|
280e5d6cb9 | ||
|
|
2a48b18b49 | ||
|
|
6bc3305340 | ||
|
|
951707b372 | ||
|
|
c76ae60092 | ||
|
|
e025901b0b | ||
|
|
e52e01a306 | ||
|
|
05b447e641 | ||
|
|
fe30b48d59 | ||
|
|
1caec25d2a | ||
|
|
6054a3a1f6 | ||
|
|
8b6555bb22 | ||
|
|
ba6ad3f20d | ||
|
|
74892e169f | ||
|
|
29e5dc66d2 | ||
|
|
d5c1e278fa | ||
|
|
6e8e426fb5 | ||
|
|
14d9b7ffe1 | ||
|
|
25f61b8a54 | ||
|
|
2f2191bc15 | ||
|
|
7d9a294745 | ||
|
|
5f4badf716 | ||
|
|
778f9582b6 | ||
|
|
22f569c36d | ||
|
|
b4bc12a985 | ||
|
|
884f1a36f9 | ||
|
|
211f55fdaf | ||
|
|
dd013c892c | ||
|
|
225dc954f1 | ||
|
|
5364e59da8 | ||
|
|
8172e59ccf | ||
|
|
73af5ffe7e | ||
|
|
42d7deb210 | ||
|
|
b12b52bf38 | ||
|
|
040329b256 | ||
|
|
58e6217e73 | ||
|
|
bc3f028082 | ||
|
|
e08984bb3f | ||
|
|
b9b3acf7f2 | ||
|
|
721585c117 | ||
|
|
851d969e9c | ||
|
|
35825a6bb5 | ||
|
|
23af517342 | ||
|
|
4874d0c120 | ||
|
|
3d5ddc8679 | ||
|
|
d0c032710d | ||
|
|
8083ab30bd | ||
|
|
2564dcbd6d | ||
|
|
6d3b1b72b5 | ||
|
|
2860294d86 | ||
|
|
6af4bed9fa | ||
|
|
f7163f8dd7 | ||
|
|
59c51a88ce | ||
|
|
b1b9ce2959 | ||
|
|
a7413c3e75 | ||
|
|
e27e0c8e51 | ||
|
|
e29db89706 | ||
|
|
4a6d365860 | ||
|
|
53c9a4633f | ||
|
|
025c778011 | ||
|
|
62c5097d6d | ||
|
|
5cab0d505b | ||
|
|
5c0333c704 | ||
|
|
71b4c1fbfa | ||
|
|
8dd16c12bc | ||
|
|
95ecbec3e4 | ||
|
|
5d14f26495 | ||
|
|
12deaa343c | ||
|
|
69f728b29b | ||
|
|
e355b99918 | ||
|
|
75959d217f | ||
|
|
ea8c653649 | ||
|
|
b37413a51c | ||
|
|
ffd614c25e | ||
|
|
39747a0031 | ||
|
|
ecbeff1856 | ||
|
|
34e4cdff87 | ||
|
|
758fa3c61a | ||
|
|
80cbb88a5a | ||
|
|
ec807c0ee8 | ||
|
|
6b2283d45b | ||
|
|
11672043c3 | ||
|
|
88e66992ed | ||
|
|
e894b39c63 | ||
|
|
57a9f0f4a6 | ||
|
|
95cc75c41d | ||
|
|
24e73971ff | ||
|
|
2395a8f1ff | ||
|
|
3fff5de46d | ||
|
|
0b503b6324 | ||
|
|
da2d004ba6 | ||
|
|
a62665313f | ||
|
|
53f67e94d8 | ||
|
|
cf3cb7a219 | ||
|
|
7816dab291 |
274
.clang-format
Normal file
274
.clang-format
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
---
|
||||
BasedOnStyle: GNU
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveBitFields:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveDeclarations:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveMacros:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: true
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCaseArrows: false
|
||||
AlignCaseColons: false
|
||||
AlignConsecutiveTableGenBreakingDAGArgColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveTableGenCondOperatorColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveTableGenDefinitionColons:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
AlignFunctionPointers: false
|
||||
PadOperators: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
Kind: Always
|
||||
OverEmptyLines: 0
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowBreakBeforeNoexceptSpecifier: Never
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseExpressionOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortCompoundRequirementOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BitFieldColonSpacing: Both
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: Always
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: true
|
||||
IndentBraces: true
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakAdjacentStringLiterals: true
|
||||
BreakAfterAttributes: Leave
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakAfterReturnType: None
|
||||
BreakArrays: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Allman
|
||||
BreakBeforeConceptDeclarations: Never
|
||||
BreakBeforeInlineASMColon: OnlyMultiline
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakFunctionDefinitionParameters: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: true
|
||||
BreakTemplateDeclarations: Yes
|
||||
ColumnLimit: 128
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: ^"(llvm|llvm-c|clang|clang-c)/
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: ^(<|"(gtest|gmock|isl|json)/)
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: .*
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: (Test)?$
|
||||
IncludeIsMainSourceRegex: ""
|
||||
IndentAccessModifiers: true
|
||||
IndentCaseBlocks: false
|
||||
IndentCaseLabels: true
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentRequiresClause: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertBraces: false
|
||||
InsertNewlineAtEOF: false
|
||||
InsertTrailingCommas: None
|
||||
IntegerLiteralSeparator:
|
||||
Binary: 0
|
||||
BinaryMinDigits: 0
|
||||
Decimal: 0
|
||||
DecimalMinDigits: 0
|
||||
Hex: 0
|
||||
HexMinDigits: 0
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLines:
|
||||
AtEndOfFile: false
|
||||
AtStartOfBlock: true
|
||||
AtStartOfFile: true
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: LF
|
||||
MacroBlockBegin: ""
|
||||
MacroBlockEnd: ""
|
||||
MainIncludeChar: Quote
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PPIndentWidth: -1
|
||||
PackConstructorInitializers: BinPack
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakScopeResolution: 500
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PenaltyReturnTypeOnItsOwnLine: 1000
|
||||
PointerAlignment: Right
|
||||
QualifierAlignment: Left
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RemoveParentheses: Leave
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SkipMacroDefinitionBody: false
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: LexicographicNumeric
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeJsonColon: false
|
||||
SpaceBeforeParens: ControlStatementsExceptControlMacros
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: false
|
||||
AfterForeachMacros: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterIfMacros: false
|
||||
AfterOverloadedOperator: false
|
||||
AfterPlacementOperator: true
|
||||
AfterRequiresInClause: false
|
||||
AfterRequiresInExpression: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParens: Never
|
||||
SpacesInParensOptions:
|
||||
ExceptDoubleParentheses: false
|
||||
InConditionalStatements: false
|
||||
InCStyleCasts: false
|
||||
InEmptyParentheses: false
|
||||
Other: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
TableGenBreakInsideDAGArg: DontBreak
|
||||
UseTab: Never
|
||||
VerilogBreakBetweenInstancePorts: true
|
||||
WhitespaceSensitiveMacros:
|
||||
- BOOST_PP_STRINGIZE
|
||||
- CF_SWIFT_NAME
|
||||
- NS_SWIFT_NAME
|
||||
- PP_STRINGIZE
|
||||
- STRINGIZE
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
Language: Cpp
|
||||
9
.clang-tidy
Normal file
9
.clang-tidy
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
Checks: 'clang-analyzer-*,cppcoreguidelines-*,modernize-*,bugprone-*,performance-*,readability-*,readability-non-const-parameter,misc-const-correctness,misc-use-anonymous-namespace,google-explicit-constructor,-modernize-use-trailing-return-type,-bugprone-exception-escape,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-bugprone-easily-swappable-parameters,-cppcoreguidelines-non-private-member-variables-in-classes'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
CheckOptions:
|
||||
- key: readability-magic-numbers.IgnoredFloatingPointValues
|
||||
value: '0.0;1.0;100.0;'
|
||||
- key: readability-magic-numbers.IgnoredIntegerValues
|
||||
value: '0;1;2;3;4;5;6;7;8;9;'
|
||||
17
.editorconfig
Normal file
17
.editorconfig
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[Makefile]
|
||||
indent_style = tab
|
||||
trim_trailing_whitespace = false
|
||||
11
.gitattributes
vendored
Normal file
11
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# Set the default behavior for all files.
|
||||
* text=auto eol=lf
|
||||
|
||||
# Normalized and converts to native line endings on checkout.
|
||||
*.c text
|
||||
*.cc text
|
||||
*.cxx
|
||||
*.cpp text
|
||||
*.h text
|
||||
*.hxx text
|
||||
*.hpp text
|
||||
4
.github/FUNDING.yml
vendored
Normal file
4
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: J-D-K
|
||||
ko_fi: j_d_k
|
||||
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
name: Bug Report
|
||||
about: Report a reproducible bug.
|
||||
title: "Bug: "
|
||||
labels: "bug"
|
||||
---
|
||||
|
||||
**Describe the bug:**
|
||||
|
||||
Describe the bug or behavior to the best of your ability.
|
||||
|
||||
**Steps needed to reproduce:**
|
||||
|
||||
Describe what you were doing when the bug occurred.
|
||||
|
||||
**Expected behavior:**
|
||||
|
||||
Describe what you expected to happen.
|
||||
|
||||
**What happens instead:**
|
||||
|
||||
Describe what happened instead.
|
||||
|
||||
**Log file output:**
|
||||
|
||||
Check `sdmc:/config/JKSV/JKSV.log` for any meaningful output that may be useful in diagnosing the bug in question. The last lines should be the most valuable.
|
||||
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
name: Feature Request
|
||||
about: Request a feature for JKSV
|
||||
title: "[Request]: "
|
||||
labels: request
|
||||
---
|
||||
|
||||
**Request:**
|
||||
|
||||
Describe what you would like JKSV to do that it can't already. Please note, adding different file hosting is dependent on how their API works and how much information they require to use it.
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -13,3 +13,7 @@ JKSV.nacp
|
|||
JKSV.nro
|
||||
JKSV.nso
|
||||
JKSV.pfs0
|
||||
|
||||
#sometimes I give jksv to people and forget about this.
|
||||
JKSV.zip
|
||||
JKSV.nro.zip
|
||||
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
[submodule "Libraries/FsLib"]
|
||||
path = Libraries/FsLib
|
||||
url = https://github.com/J-D-K/FsLib.git
|
||||
[submodule "Libraries/SDLLib"]
|
||||
path = Libraries/SDLLib
|
||||
url = https://github.com/J-D-K/SDLLib.git
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
# This is mainly for IDE Support (CLION), not for building (use Makefile directly).
|
||||
cmake_minimum_required(VERSION 3.8)
|
||||
project(JKSV)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
set(SOURCE_FILES
|
||||
src/cfg.cpp
|
||||
src/curlfuncs.cpp
|
||||
src/data.cpp
|
||||
src/fs.cpp
|
||||
src/gd.cpp
|
||||
src/gfx.cpp
|
||||
src/main.cpp
|
||||
src/rfs.cpp
|
||||
src/type.cpp
|
||||
src/ui.cpp
|
||||
src/util.cpp
|
||||
src/webdav.cpp
|
||||
src/fs/dir.cpp
|
||||
src/fs/remote.cpp
|
||||
src/fs/file.cpp
|
||||
src/fs/fsfile.c
|
||||
src/fs/zip.cpp
|
||||
src/gfx/textureMgr.cpp
|
||||
src/ui/ext.cpp
|
||||
src/ui/fld.cpp
|
||||
src/ui/fm.cpp
|
||||
src/ui/miscui.cpp
|
||||
src/ui/sett.cpp
|
||||
src/ui/sldpanel.cpp
|
||||
src/ui/thrdProc.cpp
|
||||
src/ui/ttl.cpp
|
||||
src/ui/ttlview.cpp
|
||||
src/ui/uistr.cpp
|
||||
src/ui/usr.cpp)
|
||||
|
||||
# Specify external includes here
|
||||
include_directories(./inc)
|
||||
include_directories(./inc/fs)
|
||||
include_directories(./inc/gfx)
|
||||
include_directories(./inc/ui)
|
||||
|
||||
include_directories($ENV{DEVKITPRO}/devkitA64/aarch64-none-elf/include)
|
||||
include_directories($ENV{DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/10.1.0/include)
|
||||
include_directories($ENV{DEVKITPRO}/libnx/include)
|
||||
include_directories($ENV{DEVKITPRO}/portlibs/switch/include)
|
||||
include_directories($ENV{DEVKITPRO}/portlibs/switch/include/freetype2)
|
||||
|
||||
add_executable(JKSV ${SOURCE_FILES})
|
||||
1
Libraries/FsLib
Submodule
1
Libraries/FsLib
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 995054e0d28ca9d4bf5134b10493ecebb51a7ab9
|
||||
1
Libraries/SDLLib
Submodule
1
Libraries/SDLLib
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 726c56c1a2ed4065c2efaaf2a283aa3c7af75cb7
|
||||
42
Makefile
42
Makefile
|
|
@ -32,13 +32,14 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||
#---------------------------------------------------------------------------------
|
||||
TARGET := JKSV
|
||||
BUILD := build
|
||||
SOURCES := src src/ui src/fs src/gfx
|
||||
SOURCES := source source/appstates source/config source/curl source/data source/fs \
|
||||
source/logging source/remote source/strings source/sys source/tasks source/ui
|
||||
DATA := data
|
||||
INCLUDES := inc inc/ui inc/fs inc/gfx
|
||||
INCLUDES := include ./Libraries/FsLib/Switch/FsLib/include ./Libraries/SDLLib/SDL/include
|
||||
EXEFS_SRC := exefs_src
|
||||
APP_TITLE := JKSV
|
||||
APP_AUTHOR := JK
|
||||
APP_VERSION := 11.5.2024
|
||||
APP_VERSION := 09.13.2025
|
||||
ROMFS := romfs
|
||||
ICON := icon.jpg
|
||||
|
||||
|
|
@ -47,16 +48,20 @@ ICON := icon.jpg
|
|||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
override CFLAGS += $(INCLUDE) -D__SWITCH__
|
||||
override CFLAGS += `sdl2-config --cflags` `freetype-config --cflags` `curl-config --cflags`
|
||||
override CFLAGS += -g -Wall -O2 -ffunction-sections -ffast-math $(ARCH) $(DEFINES)
|
||||
# NOTE: For some reason, devkitpro no longer has freetype-config included? Also, using pkg-config causes conflicts with
|
||||
# my local pkg-config and I don't feel like dealing with CMake for all of this right now.
|
||||
CFLAGS := $(INCLUDE) -D__SWITCH__ `sdl2-config --cflags` `curl-config --cflags`\
|
||||
-g -Wall -O3 -Os -ffunction-sections -ffast-math -fmax-errors=1 \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
|
||||
CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=c++23
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
|
||||
LIBS := `sdl2-config --libs` `freetype-config --libs` `curl-config --libs` -lSDL2_image -lwebp -lpng -ljpeg -lz -lminizip -ljson-c -ltinyxml2 -lnx
|
||||
LIBS := ../Libraries/FsLib/Switch/FsLib/lib/libFsLib.a ../Libraries/SDLLib/SDL/lib/libSDL.a \
|
||||
`sdl2-config --libs` -lfreetype -lharfbuzz `curl-config --libs` -lSDL2_image \
|
||||
-lwebp -lpng -ljpeg -lz -lminizip -ljson-c -ltinyxml2 -lnx -lbz2 -lz
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
|
|
@ -141,25 +146,38 @@ ifneq ($(ROMFS),)
|
|||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: $(BUILD) clean all
|
||||
.PHONY: $(BUILD) FsLib SDLLib clean all
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(BUILD)
|
||||
all: FsLib SDLLib $(BUILD)
|
||||
|
||||
$(BUILD):
|
||||
$(BUILD): FsLib SDLLib
|
||||
@[ -d $@ ] || mkdir -p $@
|
||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
FsLib:
|
||||
@$(MAKE) -C ./Libraries/FsLib/Switch/FsLib/ -j
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
SDLLib:
|
||||
@$(MAKE) -C ./Libraries/SDLLib/SDL/ -j
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@$(MAKE) -C ./Libraries/FsLib/Switch/FsLib clean
|
||||
@$(MAKE) -C ./Libraries/SDLLib/SDL clean
|
||||
@rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
send: $(BUILD)
|
||||
@nxlink $(TARGET).nro
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
debug: $(BUILD)
|
||||
@nxlink -s $(TARGET).nro
|
||||
|
||||
|
|
|
|||
191
README.MD
191
README.MD
|
|
@ -1,108 +1,107 @@
|
|||
# JKSV
|
||||
# JKSV Rewrite
|
||||
|
||||
JK's Save Manager Switch Edition.
|
||||
<p align="center">
|
||||
If you appreciate my work, or if JKSM or JKSV has gotten you out of a jam, please consider supporting development through a donation. Any contribution is appreciated, but never required! Creating and maintaining these tools takes a lot of time and effort.
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href='https://ko-fi.com/W7W51JF9W6' target='_blank'><img height='42' style='border:px;height:42px;' src='https://storage.ko-fi.com/cdn/kofi3.png?v=6' border='0' alt='Support me for the countless hours I poured into JKSV' /></a>
|
||||
</p>
|
||||
<img src="https://i.imgur.com/aUrq46c.png" />
|
||||
|
||||
<img src="https://i.imgur.com/yLcTPzt.jpg"/>
|
||||
## Rewritten from the ground up:
|
||||
|
||||
## Info
|
||||
This started as a simple, straight port of my 3DS save manager I publicly released in 2016. Despite not originally wanting to take it too far, I continued working on it for fun when I can. Currently it can:
|
||||
1. Dump and restore account save data.
|
||||
2. Dump and restore device saves shared by all users (Games such as Animal Crossing).
|
||||
3. Dump and restore BCAT Data.
|
||||
4. Dump and restore cache Saves.
|
||||
5. Dump system save data.
|
||||
* Dumping this data is always enabled, but writing back needs to be enabled from the options menu. Writing to this can be very dangerous.
|
||||
* Processes can be terminated from the Extras menu allowing you to open even more of these and explore more.
|
||||
6. Export save data to folders like the orignal or compressed zip files to save space.
|
||||
7. Upload and download save backups to [Google Drive](./REMOTE_INSTRUCTIONS.MD#gdrive) if it is configured.
|
||||
8. Upload and download save backups to [WebDav](./REMOTE_INSTRUCTIONS.MD#webdav) if it is configured.
|
||||
9. Create save data so the user no longer needs to boot games to import saves.
|
||||
* Titles can be rescanned from the Extras menu. For example, if you insert a game card while JKSV is open, rescanning will load and add it to the save creation menu(s).
|
||||
10. Export and use SVI files to create save data for titles not installed on your system. For games that detect other game saves to unlock content.
|
||||
* SVI files are simply the title ID, NACP, and icon packed into a file. Placing them in `JKSV/svi` will load them as if they are any other game on your switch. They will appear in the save creation menus with the rest.
|
||||
11. Extend save data containers to any size the user wants or automatically if the save cannot fit into the current one.
|
||||
12. Delete save data from the system.
|
||||
13. Reset save data as if the game was never launched.
|
||||
14. Display stats and information about the game/save: Play time, launch count, title ID (TID), save ID(SID)/name of save file on user nand partition, etc.
|
||||
15. Open and explore bis storage partitions via the Extras menu
|
||||
* BIS Storage is opened inside a basic filebrowser. The partition's listing is on the left. Your SD is on the right.
|
||||
* Only copying to SD and file properties work on BIS partitions. Writing to and deleting are disabled unless enabled like system save data.
|
||||
16. Misc Extras:
|
||||
* Ability to remove downloaded firmware updates from NAND. This is located under Extras.
|
||||
* Terminating processes by [ID](https://switchbrew.org/wiki/Title_list#System_Modules). Allowing you to dump normally unopenable system archives.
|
||||
* Mount by System Save [ID](https://switchbrew.org/wiki/Flash_Filesystem#System_Savegames). Normally used when the terminated process makes JKSV unable to rescan titles without the Switch crashing.
|
||||
* Mount and open RomFS of process the homebrew menu takes over (if launched as NRO).
|
||||
* Hold R while opening a game or applet with Atmosphere so the homebrew menu loads. Open JKSV and press minus and select **Mount Process RomFS**. The romfs of the app should appear in the browser along with your SD on the right.
|
||||
JKSV's rewrite aims to accomplish the following:
|
||||
- **Clean up and modernize the codebase:** The original master branch code became a mess over time and is extremely difficult to navigate and maintain.
|
||||
- **Zero global variables:** Everything is encapsulated via interfaces. This alone makes the rewrite easier to work with and **much** less fragile in comparison to the original.
|
||||
- **Improved error logging:** The master branch did an extremely poor job at logging errors. The rewrite corrects this greatly. Each error is logged with the file, line, and column making errors and bugs easier to track down.
|
||||
- **Designed with translations in mind:** Unlike the original, translations weren't a feature that were tacked on later. This also made the original difficult to maintain.
|
||||
- **Use standard formats:** JKSV originally used a custom file parser for data files. This has been removed in favor of JSON using libjson-c.
|
||||
- **Uses [FsLib](https://github.com/J-D-K/FsLib) instead of [fs_dev.c](https://github.com/switchbrew/libnx/blob/master/nx/source/runtime/devices/fs_dev.c):**
|
||||
- All file operations are handled using FsLib. FsLib is a C++ wrapper I wrote around libnx's FS API.
|
||||
- FsLib also handles SD card redirection so libraries that depend on C standard I/O can read and write files to and from the SD card.
|
||||
- **More convenient Google Drive login.**
|
||||
- **Improve WebDav Support and code.**
|
||||
- **Title Cache:** Titles found on the system are cached the same way [JKSM](https://github.com/J-D-K/JKSM) was. This improves boot time greatly on higher Switch firmware versions.
|
||||
- The title cache is also **auto-invalidating**. No need to manually update it like JKSM on 3DS.
|
||||
- **_Proper_ use of C++ features:**
|
||||
- **Polymorphism and state patterns** instead of scattered global variables and logic.
|
||||
- **Smart pointers** to enure no memory leaks can occur.
|
||||
- **C APIs wrapped in smart pointers and classes** to ensure proper cleanup.
|
||||
- **Templated task system** to reduce code duplication and complexity.
|
||||
- **SDL textures** are all wrapped and managed by a central texture manager.
|
||||
|
||||
**NOTE: Some features may require building JKSV from source. I am extremely picky and only release when I am satisfied and sure things work 100% as expected.**
|
||||
JKSV's rewrite is a ground-up rewrite. It shares none of the original's code **at all**. **Everything** has been reworked and rewritten.
|
||||
|
||||
## Quick Guide
|
||||
1. Main/User Menu
|
||||
* A Selects the currently highlighted user and allows you to browse their titles.
|
||||
* Y Dumps the save data for all users.
|
||||
* X opens the sub menu of options for the currently highlighted user:
|
||||
* Dump All for [X] dumps all of the saves for the highlighted user.
|
||||
* Create save data opens a list of games found on your switch and will allow to create save data for them without needing to start the games.
|
||||
* SVI files located in `JKSV/svi` will also be loaded and added to this list. These are to create save data for games not currently on the system. This is for games that search for other saves to unlock extra content.
|
||||
* Cache saves require a cache index number to be created. This information can be found under information for a cache save when being exported.
|
||||
* Create All Save Data creates save data for every title on your system for the selected user.
|
||||
* Delete All Save Data deletes all save data for the selected user. This is permanent.
|
||||
* Settings and Extras below.
|
||||
## Features:
|
||||
- **Supports all save data types used on Nintendo Switch:**
|
||||
- **Account** (User)
|
||||
- **System**
|
||||
- **BCAT**
|
||||
- **Device / Shared**
|
||||
- **Temporary**
|
||||
- **Cache**
|
||||
- **System BCAT**
|
||||
- **Export Options:**
|
||||
- Standard, unpacked folders for editors.
|
||||
- ZIP for better compatibility.
|
||||
* **NOTE: ZIP is required and enforced for cloud backup!**
|
||||
- **All At Once:**
|
||||
- JKSV can backup all the save data on the system or for individual users at once.
|
||||
- **Cloud Support:**
|
||||
- If configured, JKSV currently supports:
|
||||
- **Google Drive**
|
||||
- **WebDav**
|
||||
- JKSV can be configured to upload these automatically.
|
||||
- **Create Save Data:**
|
||||
- JKSV can create save data for any title on your system by **itself**. No need to start a game to import data for it.
|
||||
- JKSV can create save data for every title found on your system **at once** for a single user.
|
||||
- **SVI File Support:**
|
||||
- Import and create save data for titles not installed on your system.
|
||||
- **NOTE: These are not properly installed to the system. Use at your own discretion!**
|
||||
- **Resize save data:**
|
||||
- JKSV can extend save data to any size you would like. This is useful for games such as Minecraft.
|
||||
- **Cleanup Tools**
|
||||
- JKSV features functions and tools to make cleanup less of a chore compared to Nintendo's Data Management and confirmation prompts:
|
||||
- Just hold A for three seconds to:
|
||||
- Delete save data for individual games.
|
||||
- Delete all save data for a single user at once.
|
||||
- **Statistics:**
|
||||
- View basic data and statistics about the save and title.
|
||||
- **Customizable:**
|
||||
- JKSV features many options to customize it to your liking.
|
||||
- **Safety:**
|
||||
- JKSV can require holding to complete destructive operations or be set to make quick automatic backups upon restoring backups.
|
||||
|
||||
2. Title/Game Select
|
||||
* A selects and opens the backup menu.
|
||||
* Adding `.zip` to the end of your file name will force zip regardless of whether it's enabled or not.
|
||||
* Y Favorites a title and pushes it to the top of your games.
|
||||
* L and R jump forward down your games.
|
||||
* X opens the title options menu:
|
||||
* Information displays stats about the game for the current user.
|
||||
* Blacklist adds the title to a list that is not displayed.
|
||||
* Change Output Folder changes the folder to which the game's saves are written.
|
||||
* Open in File Mode opens the save in a basic file browser.
|
||||
* Delete All Save Backups deletes all of the backups for the current title.
|
||||
* Reset Save Data wipes the save clean as if it was never run.
|
||||
* Delete Save Data deletes the save data for the title from the system. This is the same as doing it from the Switch's data management setting.
|
||||
* Extend Save Data extends the container for the current title. This is also done automatically if the save being imported is too large for the container.
|
||||
* Different games have different limits. Most games do not need this at all. A few will take advantage of a larger container, others extend theirs at times and will need larger containers than created by default.
|
||||
* Export SVI exports the data needed to create save data for the current title to `JKSV/ncap/[TID].svi`. This is just the title ID, NACP, and icon of the title. These can be used to create save data for games not installed on your system.
|
||||
|
||||
4. File Mode
|
||||
* A opens directories.
|
||||
* B goes back up a folder if possible.
|
||||
* X opens a small menu of options for files and directories:
|
||||
* Copy to [X] - Copies the currently selected item to the location opened on the other panel. Selecting the first `.` will use the directory opened as root to copy.
|
||||
* Delete deletes the currently selected item.
|
||||
* Rename renames the currently selected item.
|
||||
* Make Dir creates a folder.
|
||||
* Properties gets file size and directory size.
|
||||
* ZL or ZR Change the controlled menu.
|
||||
|
||||
5. Settings
|
||||
* Empty Trash Bin deletes all backups inside the `_TRASH_` folder. The trash bin feature can be disabled further down.
|
||||
* Check For Updates checks github for updates to JKSV. This currently only updates the NRO release. Maybe NSP later.
|
||||
* Set JKSV Save Output Folder allows you to set where JKSV's working directory is. Files and folders should be relocated for you.
|
||||
* Edit Blacklisted Titles allows you to removed titles blacklisted from being shown.
|
||||
* Delete All Save Backups wipes JKSV's folder of all save backups.
|
||||
|
||||
5. Extras
|
||||
* SD To SD Browser opens the filebrowser with your SD open in both panels
|
||||
* BIS: [X] opens partition [X] in the filebrowser.
|
||||
* Remove Update deletes system updates downloaded from Nintendo and asks to reboot the system to get rid of the update nag.
|
||||
* Terminate Process asks for a title ID to terminate.
|
||||
* Mount System Save asks for the save ID to mount. This is for when JKSV is unable to rescan with a process terminated.
|
||||
* Rescan Titles reloads save data information. This can be used to reload after a process is terminated or when options are changed.
|
||||
* Mount Process RomFS opens the title's romfs that is taken over to launch the homebrew menu. This only works as an NRO. The NSP will only open JKSV's own RomFS.
|
||||
* Backup JKSV folder writes the entire JKSV folder to a ZIP archive and places it in your JKSV folder.
|
||||
|
||||
**NOTE**: Press Plus to Exit JKSV. JKSV saves all config, favorites, and the blacklist when exited. Pressing the home button and closing that way will not allow this to take place.
|
||||
## Remote Storage / Upload instructions.
|
||||
Detailed instructions for how to use JKSV's Google Drive and WebDav features can be found **[here](https://switch.hacks.guide/homebrew/jksv.html)**.
|
||||
|
||||
## Building:
|
||||
1. Requires [devkitPro](https://devkitpro.org/) and [libnx](https://github.com/switchbrew/libnx)
|
||||
2. `dkp-pacman -S switch-curl switch-freetype switch-libjpeg-turbo switch-tinyxml2 switch-libjson-c switch-libpng switch-libwebp switch-sdl2 switch-sdl2_gfx switch-sdl2_image switch-zlib`
|
||||
|
||||
1. Requires [devkitPro](https://devkitpro.org/) and [libnx](https://github.com/switchbrew/libnx).
|
||||
|
||||
2. Select Switch Development when installing or follow the instructions [here](https://devkitpro.org/wiki/Getting_Started) if you're not running Windows.
|
||||
|
||||
3. Install the following libraries using pacman and/or devkitpro's MSYS2 installation:
|
||||
- **switch-bzip2**
|
||||
- **switch-curl**
|
||||
- **switch-freetype**
|
||||
- **switch-harfbuzz**
|
||||
- **switch-libjpeg-turbo**
|
||||
- **switch-libjson-c**
|
||||
- **switch-libpng**
|
||||
- **switch-libwebp**
|
||||
- **switch-sdl2**
|
||||
- **switch-sdl2_image**
|
||||
- **switch-tinyxml2**
|
||||
- **switch-zlib**
|
||||
4. Clone JKSV's directory using the command `git clone --recurse-submodules https://github.com/J-D-K/JKSV.git` so you clone the libraries I've built for JKSV included.
|
||||
|
||||
5. Press Y while in the Switch Homebrew menu, navigate to the directory JKSV was cloned into on your PC, and type `make -j send`. JKSV should build and nxlink will attempt to send it to your Switch.
|
||||
|
||||
## Credits and Thanks:
|
||||
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8 for loading system font with Freetype. All other font handling code (converting to SDL2, resizing on the fly, checking for glyphs, cache, etc) is my own.
|
||||
* [Iguniisu](https://github.com/igniscitrinus) for the icon.
|
||||
* Uses graphics from [Twemoji](https://github.com/twitter/twemoji) covered by the [Creative Commons License](https://creativecommons.org/licenses/by/4.0/legalcode)
|
||||
* [Leo](https://github.com/qazrfv1234) For the Traditional Chinese translation
|
||||
* [JamePeng](https://github.com/JamePeng) For the Simplified Chinese translation.
|
||||
|
||||
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8 for loading system font with Freetype.
|
||||
|
||||
* Everyone that has contributed to translating and fixing the translations for JKSV.
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
# Remote Storage
|
||||
|
||||
⚠️ **WARNING** ⚠️: Breaking change with Version 07.27.2024. See [here](#remote-changelog)
|
||||
|
||||
## <a name="gdrive"></a><center> How to use Google Drive with JKSV </center>
|
||||
**USING GOOGLE DRIVE WITH JKSV CURRENTLY REQUIRES BUILDING IT YOURSELF. I AM VERY BUSY LATELY AND THINGS WILL ONLY GET FINISHED WHEN I HAVE TIME. Thanks, sorry for yelling.**
|
||||
|
||||
**NOTE: As of Feb 2023, JKSV now uses the JSON downloaded from Google directly instead of editing JKSV's configuration file.**
|
||||
|
||||
**Google only allows unverified apps to have up to 100 test users. Not only would this limit be filled within minutes, but each user has to manually added. People have been asking for some kind of cloud support since I wrote JKSM on 3DS and this is my way to support it while getting around Google's restrictions.**
|
||||
|
||||
**Note: Due to Google's restrictions on unverified apps, you will be required to login once every seven days. There is nothing I can do about this at the moment.**
|
||||
|
||||
|
||||
1. Go to https://console.cloud.google.com/cloud-resource-manager, if this is your first time, accept the terms and you should now have the dashboard in front of you.
|
||||
2. Click `CREATE PROJECT` on the next screen.<br><center><img src="https://i.imgur.com/9SDS2e0.png" /></center>
|
||||
3. On the next screen name your project JKSV. Organization is not required. Click create.
|
||||
4. Give it a few seconds and the project should be created.
|
||||
5. In the top left corner of your screen, click the navigation menu to the left of where it says **Google Cloud**. Find **Enabled APIs and services**. You may need to refresh the page if it doesn't update automatically to continue. <br><center><img src="https://i.imgur.com/JhqOpgc.png" /></center>
|
||||
6. **Double check at this point to make 100% sure JKSV is the active project just in case it is not.** <br><center><img src="https://i.imgur.com/U49aIcb.png" /></center>
|
||||
7. Once the dashboard loads, click **+ENABLE APIS AND SERVICES**. <br><center><img src="https://i.imgur.com/qaIhjID.png" /></center>
|
||||
8. Scroll down a little and find Google Drive API under Google Workspace.<br><center><img src="https://i.imgur.com/cAC7h1r.png" /></center>
|
||||
9. Click on it and click Enable on the next screen.
|
||||
10. On the next screen, Google should be informing you that you need to create credentials in order to use Drive. Click Create Credentials.<br><center><img src="https://i.imgur.com/CRhFXQ4.png" /></center>
|
||||
11. Under **Which API are you using?**, find **Cloud Storage API**. Under **What data will you be accessing?**, select **User data**. Click **Next**. <br><center><img src="https://i.imgur.com/fiulRpn.png" /></center>
|
||||
12. Fill out the following screen. **Save and continue**.
|
||||
13. Click **Add or Remove Scopes**.
|
||||
14. Find **.../auth/drive** in the API list, select it, and click update. **Save and Continue**.
|
||||
15. At this point you should be at a section named **OAuth Client ID**. Select **Desktop app**, name it **JKSV** and click **Create**.
|
||||
16. Download the credentials saved in JSON format for later. Click **Done**.
|
||||
17. Next, open the navigation menu in the top left again. Go down to **APIs and Services** and click on **OAuth consent screen**.<br><center><img src="https://i.imgur.com/OrMtG1x.png" /></center>
|
||||
18. Scroll down to the section named **Test users**. Add yourself as a test user. This concludes the Google side of things.<br><center><img src="https://i.imgur.com/RTV2LMZ.png" /></center>
|
||||
19. Next, find the JSON file you downloaded earlier. Copy it or send it via FTP to the following folder on your SD Card: `SD:/config/JKSV/`
|
||||
20. The next time you start JKSV on your Switch, you should be prompted to login to Google via the Switch's web browser. Ta-da!
|
||||
|
||||
## <a name="webdav"></a><center> How to use WebDav with JKSV </center>
|
||||
**NOTE: If you have [GDrive](#gdrive) configured (via JSON), it takes preference over WebDav**
|
||||
|
||||
1. Create a file `webdav.json` with the following content:
|
||||
```json
|
||||
{
|
||||
"origin": "https://your-webdav-server",
|
||||
"basepath": "optional-base-path",
|
||||
"username": "testuser",
|
||||
"password": "testpassword"
|
||||
}
|
||||
```
|
||||
- `origin` (mandatory): protocol + serveraddress + (optional port), e.g. `https://your-webdav-server` or `http://localhost:8080` - **No trailing slash**
|
||||
- `basepath` (optional): e.g. `dir`, `dir/subdir` must exist beforehand - **No leading AND trailing slash** - if your path uses special characters or spaces, they must be on URI encoding, by example `Game Saves` should be stored as `Game%20Saves`.
|
||||
- `username` (optional): username, if server uses credentials
|
||||
- `password` (optional): username, if server uses credentials
|
||||
2. Copy file to following folder on your card `SD:/config/JKSV/`
|
||||
3. The next time you start JKSV on your Switch, you should get a popup about the Webdav status
|
||||
4. If problems arise, check the log at `SD:/JKSV/log.txt`
|
||||
|
||||
## Remote Changelog
|
||||
- **07.27.2024**: **Breaking Change**. "Unsafe" characters were removed from titlename on the remote directory. That means,
|
||||
that if you had existing safes under a title with unsafe characters, you will need to move them manually.
|
||||
39
inc/cfg.h
39
inc/cfg.h
|
|
@ -1,39 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace cfg
|
||||
{
|
||||
typedef enum
|
||||
{
|
||||
ALPHA,
|
||||
MOST_PLAYED,
|
||||
LAST_PLAYED
|
||||
} sortTypes;
|
||||
|
||||
void resetConfig();
|
||||
void loadConfig();
|
||||
void saveConfig();
|
||||
|
||||
bool isBlacklisted(const uint64_t& tid);
|
||||
void addTitleToBlacklist(void *a);
|
||||
void removeTitleFromBlacklist(const uint64_t& tid);
|
||||
|
||||
bool isFavorite(const uint64_t& tid);
|
||||
void addTitleToFavorites(const uint64_t& tid);
|
||||
|
||||
bool isDefined(const uint64_t& tid);
|
||||
void pathDefAdd(const uint64_t& tid, const std::string& newPath);
|
||||
std::string getPathDefinition(const uint64_t& tid);
|
||||
|
||||
void addPathToFilter(const uint64_t& tid, const std::string& _p);
|
||||
|
||||
extern std::unordered_map<std::string, bool> config;
|
||||
extern std::vector<uint64_t> blacklist;
|
||||
extern std::vector<uint64_t> favorites;
|
||||
extern uint8_t sortType;
|
||||
extern std::string driveClientID, driveClientSecret, driveRefreshToken;
|
||||
extern std::string webdavOrigin, webdavBasePath, webdavUser, webdavPassword;
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define HEADER_ERROR "ERROR"
|
||||
|
||||
namespace curlFuncs
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
FILE *f;
|
||||
uint64_t *o;
|
||||
} curlUpArgs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string path;
|
||||
unsigned int size;
|
||||
uint64_t *o;
|
||||
} curlDlArgs;
|
||||
|
||||
size_t writeDataString(const char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t writeHeaders(const char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t readDataFile(char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t readDataBuffer(char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t writeDataFile(const char *buff, size_t sz, size_t cnt, void *u);
|
||||
size_t writeDataBuffer(const char *buff, size_t sz, size_t cnt, void *u);
|
||||
|
||||
std::string getHeader(const std::string& _name, std::vector<std::string> *h);
|
||||
|
||||
//Shortcuts/legacy
|
||||
std::string getJSONURL(std::vector<std::string> *headers, const std::string& url);
|
||||
bool getBinURL(std::vector<uint8_t> *out, const std::string& url);
|
||||
}
|
||||
103
inc/data.h
103
inc/data.h
|
|
@ -1,103 +0,0 @@
|
|||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "gfx.h"
|
||||
|
||||
#define BLD_MON 11
|
||||
#define BLD_DAY 5
|
||||
#define BLD_YEAR 2024
|
||||
|
||||
namespace data
|
||||
{
|
||||
//Loads user + title info
|
||||
void init();
|
||||
void exit();
|
||||
bool loadUsersTitles(bool clearUsers);
|
||||
void sortUserTitles();
|
||||
|
||||
//Draws some stats to the upper left corner
|
||||
void dispStats();
|
||||
|
||||
//Global stuff for all titles/saves
|
||||
typedef struct
|
||||
{
|
||||
NacpStruct nacp;
|
||||
std::string title, safeTitle, author;//Shortcuts sorta.
|
||||
SDL_Texture *icon = NULL;
|
||||
bool fav;
|
||||
} titleInfo;
|
||||
|
||||
//Holds stuff specific to user's titles/saves
|
||||
typedef struct
|
||||
{
|
||||
//Makes it easier to grab id
|
||||
uint64_t tid;
|
||||
FsSaveDataInfo saveInfo;
|
||||
PdmPlayStatistics playStats;
|
||||
} userTitleInfo;
|
||||
|
||||
//Class to store user info + titles
|
||||
class user
|
||||
{
|
||||
public:
|
||||
user() = default;
|
||||
user(const AccountUid& _id, const std::string& _backupName, const std::string& _safeBackupName);
|
||||
user(const AccountUid& _id, const std::string& _backupName, const std::string& _safeBackupName, SDL_Texture *img);
|
||||
|
||||
//Sets ID
|
||||
void setUID(const AccountUid& _id);
|
||||
|
||||
//Assigns icon
|
||||
void assignIcon(SDL_Texture *_icn) { userIcon = _icn; }
|
||||
|
||||
//Returns user ID
|
||||
AccountUid getUID() const { return userID; }
|
||||
u128 getUID128() const { return uID128; }
|
||||
|
||||
//Returns username
|
||||
std::string getUsername() const { return username; }
|
||||
std::string getUsernameSafe() const { return userSafe; }
|
||||
|
||||
SDL_Texture *getUserIcon(){ return userIcon; }
|
||||
void delIcon(){ SDL_DestroyTexture(userIcon); }
|
||||
|
||||
std::vector<data::userTitleInfo> titleInfo;
|
||||
void addUserTitleInfo(const uint64_t& _tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats);
|
||||
|
||||
private:
|
||||
AccountUid userID;
|
||||
u128 uID128;
|
||||
std::string username, userSafe;
|
||||
//User icon
|
||||
SDL_Texture *userIcon;
|
||||
};
|
||||
|
||||
//User vector
|
||||
extern std::vector<user> users;
|
||||
//Title data/info map
|
||||
extern std::unordered_map<uint64_t, data::titleInfo> titles;
|
||||
|
||||
//Sets/Retrieves current user/title
|
||||
void setUserIndex(unsigned _sUser);
|
||||
data::user *getCurrentUser();
|
||||
unsigned getCurrentUserIndex();
|
||||
|
||||
void setTitleIndex(unsigned _sTitle);
|
||||
data::userTitleInfo *getCurrentUserTitleInfo();
|
||||
unsigned getCurrentUserTitleInfoIndex();
|
||||
|
||||
//Gets pointer to info that also has title + nacp
|
||||
data::titleInfo *getTitleInfoByTID(const uint64_t& tid);
|
||||
|
||||
//More shortcut functions
|
||||
std::string getTitleNameByTID(const uint64_t& tid);
|
||||
std::string getTitleSafeNameByTID(const uint64_t& tid);
|
||||
SDL_Texture *getTitleIconByTID(const uint64_t& tid);
|
||||
int getTitleIndexInUser(const data::user& u, const uint64_t& tid);
|
||||
extern SetLanguage sysLang;
|
||||
|
||||
}
|
||||
55
inc/fs.h
55
inc/fs.h
|
|
@ -1,55 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <minizip/zip.h>
|
||||
#include <minizip/unzip.h>
|
||||
|
||||
#include "fs/fstype.h"
|
||||
#include "fs/file.h"
|
||||
#include "fs/dir.h"
|
||||
#include "fs/zip.h"
|
||||
#include "fs/fsfile.h"
|
||||
#include "fs/remote.h"
|
||||
#include "ui/miscui.h"
|
||||
|
||||
#define BUFF_SIZE 0x4000
|
||||
#define ZIP_BUFF_SIZE 0x20000
|
||||
#define TRANSFER_BUFFER_LIMIT 0xC00000
|
||||
|
||||
namespace fs
|
||||
{
|
||||
copyArgs *copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces);
|
||||
void copyArgsDestroy(copyArgs *c);
|
||||
|
||||
void init();
|
||||
bool mountSave(const FsSaveDataInfo& _m);
|
||||
inline bool unmountSave() { return fsdevUnmountDevice("sv") == 0; }
|
||||
bool commitToDevice(const std::string& dev);
|
||||
std::string getWorkDir();
|
||||
void setWorkDir(const std::string& _w);
|
||||
|
||||
//Loads paths to filter from backup/deletion
|
||||
void loadPathFilters(const uint64_t& tid);
|
||||
bool pathIsFiltered(const std::string& _path);
|
||||
void freePathFilters();
|
||||
|
||||
void createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t);
|
||||
void createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid);
|
||||
bool extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t);
|
||||
void extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize);
|
||||
uint64_t getJournalSize(const data::userTitleInfo *tinfo);
|
||||
uint64_t getJournalSizeMax(const data::userTitleInfo *tinfo);
|
||||
|
||||
//Always threaded
|
||||
void wipeSave();
|
||||
|
||||
void createNewBackup(void *a);
|
||||
void overwriteBackup(void *a);
|
||||
void restoreBackup(void *a);
|
||||
void deleteBackup(void *a);
|
||||
|
||||
void dumpAllUserSaves(void *a);
|
||||
void dumpAllUsersAllSaves(void *a);
|
||||
|
||||
void logOpen();
|
||||
void logWrite(const char *fmt, ...);
|
||||
}
|
||||
54
inc/fs/dir.h
54
inc/fs/dir.h
|
|
@ -1,54 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "type.h"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
void mkDir(const std::string& _p);
|
||||
void mkDirRec(const std::string& _p);
|
||||
void delDir(const std::string& _p);
|
||||
bool dirNotEmpty(const std::string& _dir);
|
||||
bool isDir(const std::string& _path);
|
||||
|
||||
//threadInfo is optional. Only for updating task status.
|
||||
void copyDirToDir(const std::string& src, const std::string& dst, threadInfo *t);
|
||||
void copyDirToDirThreaded(const std::string& src, const std::string& dst);
|
||||
void copyDirToDirCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t);
|
||||
void copyDirToDirCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev);
|
||||
void getDirProps(const std::string& path, unsigned& dirCount, unsigned& fileCount, uint64_t& totalSize);
|
||||
|
||||
class dirItem
|
||||
{
|
||||
public:
|
||||
dirItem(const std::string& pathTo, const std::string& sItem);
|
||||
std::string getItm() const { return itm; }
|
||||
std::string getName() const;
|
||||
std::string getExt() const;
|
||||
bool isDir() const { return dir; }
|
||||
|
||||
private:
|
||||
std::string itm;
|
||||
bool dir = false;
|
||||
};
|
||||
|
||||
//Just retrieves a listing for _path and stores it in item vector
|
||||
class dirList
|
||||
{
|
||||
public:
|
||||
dirList() = default;
|
||||
dirList(const std::string& _path, bool ignoreDotFiles = false);
|
||||
void reassign(const std::string& _path);
|
||||
void rescan();
|
||||
|
||||
std::string getItem(int index) const { return item[index].getItm(); }
|
||||
std::string getItemExt(int index) const { return item[index].getExt(); }
|
||||
bool isDir(int index) const { return item[index].isDir(); }
|
||||
unsigned getCount() const { return item.size(); }
|
||||
fs::dirItem *getDirItemAt(unsigned int _ind) { return &item[_ind]; }
|
||||
|
||||
private:
|
||||
std::string path;
|
||||
std::vector<dirItem> item;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
#include <switch.h>
|
||||
#include <dirent.h>
|
||||
#include <minizip/zip.h>
|
||||
#include <minizip/unzip.h>
|
||||
|
||||
#include "fs.h"
|
||||
#include "data.h"
|
||||
#include "ui.h"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
//Copy args are optional and only used if passed and threaded
|
||||
void copyFile(const std::string& src, const std::string& dst, threadInfo *t);
|
||||
void copyFileThreaded(const std::string& src, const std::string& dst);
|
||||
void copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t);
|
||||
void copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev);
|
||||
void fileDrawFunc(void *a);
|
||||
|
||||
//deletes file
|
||||
void delfile(const std::string& _p);
|
||||
|
||||
//Dumps all titles for current user
|
||||
void dumpAllUserSaves();
|
||||
|
||||
void getShowFileProps(const std::string& _path);
|
||||
void getShowDirProps(const std::string& _path);
|
||||
|
||||
bool fileExists(const std::string& _path);
|
||||
//Returns file size
|
||||
size_t fsize(const std::string& _f);
|
||||
|
||||
class dataFile
|
||||
{
|
||||
public:
|
||||
dataFile(const std::string& _path);
|
||||
~dataFile();
|
||||
void close(){ fclose(f); }
|
||||
|
||||
bool isOpen() const { return opened; }
|
||||
|
||||
bool readNextLine(bool proc);
|
||||
//Finds where variable name ends. When a '(' or '=' is hit. Strips spaces
|
||||
void procLine();
|
||||
std::string getLine() const { return line; }
|
||||
std::string getName() const { return name; }
|
||||
//Reads until ';', ',', or '\n' is hit and returns as string.
|
||||
std::string getNextValueStr();
|
||||
int getNextValueInt();
|
||||
|
||||
private:
|
||||
FILE *f;
|
||||
std::string line, name;
|
||||
size_t lPos = 0;
|
||||
bool opened = false;
|
||||
};
|
||||
|
||||
void logOpen();
|
||||
void logWrite(const char *fmt, ...);
|
||||
void logClose();
|
||||
}
|
||||
100
inc/fs/fsfile.h
100
inc/fs/fsfile.h
|
|
@ -1,100 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <stdint.h>
|
||||
|
||||
//Bare minimum wrapper around switch fs for JKSV
|
||||
#define FS_SEEK_SET 0
|
||||
#define FS_SEEK_CUR 1
|
||||
#define FS_SEEK_END 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
typedef struct
|
||||
{
|
||||
FsFile _f;
|
||||
Result error;
|
||||
s64 offset, fsize;
|
||||
} FSFILE;
|
||||
|
||||
int fsremove(const char *_p);
|
||||
Result fsDelDirRec(const char *_p);
|
||||
|
||||
char *getDeviceFromPath(char *dev, size_t _max, const char *path);
|
||||
char *getFilePath(char *pathOut, size_t _max, const char *path);
|
||||
|
||||
bool fsMkDir(const char *_p);
|
||||
|
||||
/*Opens file. Device is fetched from path. Libnx romfs doesn't work with this.
|
||||
Mode needs to be:
|
||||
FsOpenMode_Read
|
||||
FsOpenMode_Write
|
||||
FsOpenMode_Append
|
||||
*/
|
||||
bool fsfcreate(const char *_p, int64_t crSize);
|
||||
|
||||
FSFILE *fsfopen(const char *_p, uint32_t mode);
|
||||
|
||||
/*Same as above, but FsFileSystem _s is used. Path cannot have device in it*/
|
||||
FSFILE *fsfopenWithSystem(FsFileSystem *_s, const char *_p, uint32_t mode);
|
||||
|
||||
//Closes _f
|
||||
inline void fsfclose(FSFILE *_f)
|
||||
{
|
||||
if(_f != NULL)
|
||||
{
|
||||
fsFileClose(&_f->_f);
|
||||
free(_f);
|
||||
}
|
||||
}
|
||||
|
||||
//Seeks like stdio
|
||||
inline void fsfseek(FSFILE *_f, int offset, int origin)
|
||||
{
|
||||
switch(origin)
|
||||
{
|
||||
case FS_SEEK_SET:
|
||||
_f->offset = offset;
|
||||
break;
|
||||
|
||||
case FS_SEEK_CUR:
|
||||
_f->offset += offset;
|
||||
break;
|
||||
|
||||
case FS_SEEK_END:
|
||||
_f->offset = offset + _f->fsize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Returns offset
|
||||
inline size_t fsftell(FSFILE *_f) { return _f->offset; }
|
||||
|
||||
//Writes buf to file. Automatically resizes _f to fit buf
|
||||
size_t fsfwrite(const void *buf, size_t sz, size_t count, FSFILE *_f);
|
||||
|
||||
//Reads to buff
|
||||
inline size_t fsfread(void *buf, size_t sz, size_t count, FSFILE *_f)
|
||||
{
|
||||
uint64_t read = 0;
|
||||
_f->error = fsFileRead(&_f->_f, _f->offset, buf, sz * count, 0, &read);
|
||||
_f->offset += read;
|
||||
return read;
|
||||
}
|
||||
|
||||
//Gets byte from file
|
||||
inline char fsfgetc(FSFILE *_f)
|
||||
{
|
||||
char ret = 0;
|
||||
uint64_t read = 0;
|
||||
_f->error = fsFileRead(&_f->_f, _f->offset++, &ret, 1, 0, &read);
|
||||
return ret;
|
||||
}
|
||||
|
||||
//Writes byte to file
|
||||
inline void fsfputc(int ch, FSFILE *_f) { fsfwrite(&ch, 1, 1, _f); }
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "data.h"
|
||||
#include "miscui.h"
|
||||
#include "type.h"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
std::string src, dst, dev;
|
||||
zipFile z;
|
||||
unzFile unz;
|
||||
bool cleanup = false, trimZipPath = false;
|
||||
uint8_t trimZipPlaces = 0;
|
||||
uint64_t offset = 0;
|
||||
ui::progBar *prog;
|
||||
threadStatus *thrdStatus;
|
||||
Mutex arglck = 0;
|
||||
void argLock() { mutexLock(&arglck); }
|
||||
void argUnlock() { mutexUnlock(&arglck); }
|
||||
} copyArgs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FsSaveDataType type;
|
||||
uint64_t tid;
|
||||
AccountUid account;
|
||||
uint16_t index;
|
||||
} svCreateArgs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const data::userTitleInfo *tinfo;
|
||||
uint64_t extSize;
|
||||
} svExtendArgs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string path;
|
||||
bool origin = false;
|
||||
unsigned dirCount = 0;
|
||||
unsigned fileCount = 0;
|
||||
uint64_t totalSize = 0;
|
||||
} dirCountArgs;
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "../rfs.h"
|
||||
|
||||
#define JKSV_DRIVE_FOLDER "JKSV"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
extern rfs::IRemoteFS *rfs;
|
||||
extern std::string rfsRootID;
|
||||
|
||||
void remoteInit();
|
||||
void remoteExit();
|
||||
|
||||
// Google Drive
|
||||
void driveInit();
|
||||
std::string driveSignInGetAuthCode();
|
||||
|
||||
// Webdav
|
||||
void webDavInit();
|
||||
}
|
||||
18
inc/fs/zip.h
18
inc/fs/zip.h
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <minizip/zip.h>
|
||||
#include <minizip/unzip.h>
|
||||
|
||||
#include "type.h"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
//threadInfo is optional and only used when threaded versions are used
|
||||
void copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t);
|
||||
void copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces);
|
||||
void copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t);
|
||||
void copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev);
|
||||
uint64_t getZipTotalSize(unzFile unz);
|
||||
bool zipNotEmpty(unzFile unz);
|
||||
}
|
||||
66
inc/gd.h
66
inc/gd.h
|
|
@ -1,66 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "curlfuncs.h"
|
||||
#include "rfs.h"
|
||||
|
||||
#define HEADER_CONTENT_TYPE_APP_JSON "Content-Type: application/json; charset=UTF-8"
|
||||
#define HEADER_AUTHORIZATION "Authorization: Bearer "
|
||||
|
||||
#define MIMETYPE_FOLDER "application/vnd.google-apps.folder"
|
||||
|
||||
namespace drive
|
||||
{
|
||||
class gd : public rfs::IRemoteFS
|
||||
{
|
||||
public:
|
||||
void setClientID(const std::string& _clientID) { clientID = _clientID; }
|
||||
void setClientSecret(const std::string& _clientSecret) { secretID = _clientSecret; }
|
||||
void setRefreshToken(const std::string& _refreshToken) { rToken = _refreshToken; }
|
||||
|
||||
bool exhangeAuthCode(const std::string& _authCode);
|
||||
bool hasToken() { return token.empty() == false; }
|
||||
bool refreshToken();
|
||||
bool tokenIsValid();
|
||||
|
||||
void clearDriveList() { driveList.clear(); }
|
||||
// TODO: This also gets files that do not belong to JKSV
|
||||
void driveListInit(const std::string& _q);
|
||||
void driveListAppend(const std::string& _q);
|
||||
std::vector<rfs::RfsItem> getListWithParent(const std::string& _parent);
|
||||
void debugWriteList();
|
||||
|
||||
bool createDir(const std::string& _dirName, const std::string& _parent);
|
||||
// TODO: This is problematic, because multiple files could share the same name without a parent.
|
||||
bool dirExists(const std::string& _dirName);
|
||||
bool dirExists(const std::string& _dirName, const std::string& _parent);
|
||||
|
||||
bool fileExists(const std::string& _filename, const std::string& _parent);
|
||||
void uploadFile(const std::string& _filename, const std::string& _parent, curlFuncs::curlUpArgs *_upload);
|
||||
void updateFile(const std::string& _fileID, curlFuncs::curlUpArgs *_upload);
|
||||
void downloadFile(const std::string& _fileID, curlFuncs::curlDlArgs *_download);
|
||||
void deleteFile(const std::string& _fileID);
|
||||
|
||||
std::string getClientID() const { return clientID; }
|
||||
std::string getClientSecret() const { return secretID; }
|
||||
std::string getRefreshToken() const { return rToken; }
|
||||
|
||||
std::string getFileID(const std::string& _name, const std::string& _parent);
|
||||
// TODO: This is problematic, because multiple files could share the same name without a parent.
|
||||
std::string getDirID(const std::string& _name);
|
||||
std::string getDirID(const std::string& _name, const std::string& _parent);
|
||||
|
||||
size_t getDriveListCount() const { return driveList.size(); }
|
||||
rfs::RfsItem *getItemAt(unsigned int _ind) { return &driveList[_ind]; }
|
||||
|
||||
private:
|
||||
std::vector<rfs::RfsItem> driveList;
|
||||
std::string clientID, secretID, token, rToken;
|
||||
};
|
||||
}
|
||||
26
inc/gfx.h
26
inc/gfx.h
|
|
@ -1,26 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
#include "textureMgr.h"
|
||||
|
||||
namespace gfx
|
||||
{
|
||||
extern SDL_Renderer *render;
|
||||
extern gfx::textureMgr *texMgr;
|
||||
|
||||
void init();
|
||||
void exit();
|
||||
void present();
|
||||
|
||||
void drawTextf(SDL_Texture *target, int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...);
|
||||
void drawTextfWrap(SDL_Texture *target, int fontSize, int x, int y, int maxWidth, const SDL_Color* c, const char *fmt, ...);
|
||||
size_t getTextWidth(const char *str, int fontSize);
|
||||
|
||||
//Shortcuts for drawing
|
||||
void texDraw(SDL_Texture *target, SDL_Texture *tex, int x, int y);
|
||||
void texDrawStretch(SDL_Texture *target, SDL_Texture *tex, int x, int y, int w, int h);
|
||||
void texDrawPart(SDL_Texture *target, SDL_Texture *tex, int srcX, int srcY, int srcW, int srcH, int dstX, int dstY);
|
||||
void drawLine(SDL_Texture *target, const SDL_Color *c, int x1, int y1, int x2, int y2);
|
||||
void drawRect(SDL_Texture *target, const SDL_Color *c, int x, int y, int w, int h);
|
||||
void clearTarget(SDL_Texture *target, const SDL_Color *clear);
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
/*Texture manager class
|
||||
Keeps pointers to ALL textures so it is not possible to forget to free them. Also keeps code a little easier to read. A little.*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
IMG_FMT_PNG,
|
||||
IMG_FMT_JPG,
|
||||
IMG_FMT_BMP
|
||||
} imgTypes;
|
||||
|
||||
namespace gfx
|
||||
{
|
||||
class textureMgr
|
||||
{
|
||||
public:
|
||||
textureMgr() = default;
|
||||
~textureMgr();
|
||||
|
||||
void textureAdd(SDL_Texture *_tex);
|
||||
SDL_Texture *textureCreate(int _w, int _h);
|
||||
SDL_Texture *textureLoadFromFile(const char *_path);
|
||||
SDL_Texture *textureLoadFromMem(imgTypes _type, const void *_dat, size_t _datSize);
|
||||
void textureResize(SDL_Texture **_tex, int _w, int _h);
|
||||
|
||||
private:
|
||||
std::vector<SDL_Texture *> textures;
|
||||
};
|
||||
}
|
||||
53
inc/rfs.h
53
inc/rfs.h
|
|
@ -1,53 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "curlfuncs.h"
|
||||
#include <mutex>
|
||||
|
||||
#define UPLOAD_BUFFER_SIZE 0x8000
|
||||
#define DOWNLOAD_BUFFER_SIZE 0xC00000
|
||||
#define USER_AGENT "JKSV"
|
||||
|
||||
namespace rfs {
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string name, id, parent;
|
||||
bool isDir = false;
|
||||
unsigned int size;
|
||||
} RfsItem;
|
||||
|
||||
class IRemoteFS
|
||||
{
|
||||
public:
|
||||
virtual ~IRemoteFS() {} // Virtual destructor to allow correct deletion through the base class pointer
|
||||
|
||||
virtual bool createDir(const std::string& _dirName, const std::string& _parent) = 0;
|
||||
virtual bool dirExists(const std::string& _dirName, const std::string& _parent) = 0;
|
||||
virtual bool fileExists(const std::string& _filename, const std::string& _parent) = 0;
|
||||
virtual void uploadFile(const std::string& _filename, const std::string& _parent, curlFuncs::curlUpArgs *_upload) = 0;
|
||||
virtual void updateFile(const std::string& _fileID, curlFuncs::curlUpArgs *_upload) = 0;
|
||||
virtual void downloadFile(const std::string& _fileID, curlFuncs::curlDlArgs *_download) = 0;
|
||||
virtual void deleteFile(const std::string& _fileID) = 0;
|
||||
|
||||
virtual std::string getFileID(const std::string& _name, const std::string& _parent) = 0;
|
||||
virtual std::string getDirID(const std::string& _name, const std::string& _parent) = 0;
|
||||
|
||||
virtual std::vector<RfsItem> getListWithParent(const std::string& _parent) = 0;
|
||||
};
|
||||
|
||||
// Shared multi-threading definitions
|
||||
typedef struct
|
||||
{
|
||||
curlFuncs::curlDlArgs *cfa;
|
||||
std::mutex dataLock;
|
||||
std::condition_variable cond;
|
||||
std::vector<uint8_t> sharedBuffer;
|
||||
bool bufferFull = false;
|
||||
unsigned int downloaded = 0;
|
||||
} dlWriteThreadStruct;
|
||||
|
||||
extern std::vector<uint8_t> downloadBuffer;
|
||||
void writeThread_t(void *a);
|
||||
size_t writeDataBufferThreaded(uint8_t *buff, size_t sz, size_t cnt, void *u);
|
||||
}
|
||||
28
inc/type.h
28
inc/type.h
|
|
@ -1,28 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
|
||||
//Misc stuff for new menu code
|
||||
typedef void (*funcPtr)(void *);
|
||||
|
||||
class threadStatus
|
||||
{
|
||||
public:
|
||||
void setStatus(const char *fmt, ...);
|
||||
void getStatus(std::string& statusOut);
|
||||
|
||||
private:
|
||||
Mutex statusLock = 0;
|
||||
std::string status;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool running = false, finished = false;
|
||||
Thread thrd;
|
||||
ThreadFunc thrdFunc;
|
||||
void *argPtr = NULL;
|
||||
funcPtr drawFunc = NULL;//Draw func is passed threadInfo pointer too
|
||||
threadStatus *status;
|
||||
} threadInfo;
|
||||
110
inc/ui.h
110
inc/ui.h
|
|
@ -1,110 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "data.h"
|
||||
#include "gfx.h"
|
||||
|
||||
//ui headers - split up to keep a bit more organized
|
||||
#include "ui/miscui.h"
|
||||
#include "ui/uistr.h"
|
||||
#include "ui/ttlview.h"
|
||||
#include "ui/thrdProc.h"
|
||||
#include "ui/sldpanel.h"
|
||||
#include "ui/usr.h"
|
||||
#include "ui/ttl.h"
|
||||
#include "ui/fld.h"
|
||||
#include "ui/sett.h"
|
||||
#include "ui/ext.h"
|
||||
#include "ui/fm.h"
|
||||
|
||||
enum menuState
|
||||
{
|
||||
USR_SEL,
|
||||
TTL_SEL,
|
||||
ADV_MDE,
|
||||
EX_MNU,
|
||||
OPT_MNU,
|
||||
FIL_MDE
|
||||
};
|
||||
|
||||
namespace ui
|
||||
{
|
||||
//Current menu/ui state
|
||||
extern int mstate, prevState;
|
||||
|
||||
//Slide/animation scaling
|
||||
extern float animScale;
|
||||
|
||||
//Loading glyph
|
||||
extern const std::string loadGlyphArray[];
|
||||
|
||||
//pad data cause i don't know where else to put it
|
||||
extern PadState pad;
|
||||
extern HidTouchScreenState touchState;
|
||||
static inline void updateInput() { touchState = {0}; padUpdate(&pad); hidGetTouchScreenStates(&touchState, 1); }
|
||||
inline uint64_t padKeysDown() { return padGetButtonsDown(&pad); }
|
||||
inline uint64_t padKeysHeld() { return padGetButtons(&pad); }
|
||||
inline uint64_t padKeysUp() { return padGetButtonsUp(&pad); }
|
||||
|
||||
inline void changeState(int newState)
|
||||
{
|
||||
prevState = mstate;
|
||||
mstate = newState;
|
||||
}
|
||||
|
||||
//Holds theme set id
|
||||
extern ColorSetId thmID;
|
||||
|
||||
//Both UI modes need access to this
|
||||
extern std::string folderMenuInfo;
|
||||
|
||||
/*Colors
|
||||
clearClr = color to clear buffer
|
||||
txtCont = text that contrasts clearClr
|
||||
txtDiag = text color for dialogs
|
||||
*/
|
||||
extern SDL_Color clearClr, transparent, txtCont, txtDiag, rectLt, rectSh, tboxClr, sideRect, divClr, heartColor, slidePanelColor;
|
||||
|
||||
//Textbox graphics
|
||||
extern SDL_Texture *cornerTopLeft, *cornerTopRight, *cornerBottomLeft, *cornerBottomRight;
|
||||
//Menu bounding
|
||||
extern SDL_Texture *mnuTopLeft, *mnuTopRight, *mnuBotLeft, *mnuBotRight;
|
||||
|
||||
//Covers left and right of progress bar to fake being not a rectangle.
|
||||
extern SDL_Texture *progCovLeft, *progCovRight, *diaBox;
|
||||
|
||||
//Side bar from Freebird. RIP.
|
||||
extern SDL_Texture *sideBar;
|
||||
|
||||
//Sets colors and loads font for icon creation
|
||||
void initTheme();
|
||||
|
||||
//Loads graphics and stuff
|
||||
void init();
|
||||
void exit();
|
||||
|
||||
//Inits HID
|
||||
void hidInit();
|
||||
|
||||
//Adds a panel pointer to a vector since they need to be drawn over everything else
|
||||
int registerMenu(ui::menu *m);
|
||||
int registerPanel(ui::slideOutPanel *sop);
|
||||
threadInfo *newThread(ThreadFunc func, void *args, funcPtr _drawFunc);
|
||||
|
||||
//Just draws a screen and flips JIC boot takes long.
|
||||
void showLoadScreen();
|
||||
|
||||
//Clears and draws general stuff used by multiple screens
|
||||
void drawUI();
|
||||
|
||||
//switch case so we don't have problems with multiple main loops like 3DS
|
||||
bool runApp();
|
||||
|
||||
void showPopMessage(int frameCount, const char *fmt, ...);
|
||||
|
||||
//Used for multiple menu functions/callback
|
||||
void toTTL(void *);
|
||||
}
|
||||
10
inc/ui/ext.h
10
inc/ui/ext.h
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace ui
|
||||
{
|
||||
extern ui::menu *extMenu;
|
||||
void extInit();
|
||||
void extExit();
|
||||
void extUpdate();
|
||||
void extDraw(SDL_Texture *target);
|
||||
}
|
||||
19
inc/ui/fld.h
19
inc/ui/fld.h
|
|
@ -1,19 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "ui.h"
|
||||
#include "dir.h"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
//extern ui::menu *fldMenu;
|
||||
extern ui::slideOutPanel *fldPanel;
|
||||
//extern fs::dirList *fldList;
|
||||
|
||||
void fldInit();
|
||||
void fldExit();
|
||||
void fldUpdate();
|
||||
|
||||
//Populate to open menu, refresh for updating after actions
|
||||
void fldPopulateMenu();
|
||||
void fldRefreshMenu();
|
||||
}
|
||||
10
inc/ui/fm.h
10
inc/ui/fm.h
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace ui
|
||||
{
|
||||
void fmInit();
|
||||
void fmExit();
|
||||
void fmPrep(const FsSaveDataType& _type, const std::string& _dev, const std::string& _baseSDMC, bool _commit);
|
||||
void fmUpdate();
|
||||
void fmDraw(SDL_Texture *target);
|
||||
}
|
||||
165
inc/ui/miscui.h
165
inc/ui/miscui.h
|
|
@ -1,165 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "type.h"
|
||||
#include "gfx.h"
|
||||
|
||||
#define POP_FRAME_DEFAULT 130
|
||||
|
||||
#define MENU_FONT_SIZE_DEFAULT 18
|
||||
#define MENU_MAX_SCROLL_DEFAULT 15
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MENU_X,
|
||||
MENU_Y,
|
||||
MENU_RECT_WIDTH,
|
||||
MENU_RECT_HEIGHT,
|
||||
MENU_FONT_SIZE,
|
||||
MENU_MAX_SCROLL
|
||||
} menuParams;
|
||||
|
||||
//For smaller classes that aren't easy to get lost in and general functions
|
||||
namespace ui
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
std::string text;
|
||||
bool hold;
|
||||
funcPtr confFunc, cancelFunc;
|
||||
void *args;
|
||||
unsigned lgFrame = 0, frameCount = 0;//To count frames cause I don't have time and am lazy
|
||||
} confirmArgs;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
funcPtr func = NULL;
|
||||
void *args = NULL;
|
||||
HidNpadButton button = (HidNpadButton)0;
|
||||
} menuOptEvent;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SDL_Texture *icn = NULL;
|
||||
std::string txt;
|
||||
int txtWidth;
|
||||
std::vector<menuOptEvent> events;
|
||||
} menuOpt;
|
||||
|
||||
class menu
|
||||
{
|
||||
public:
|
||||
menu() = default;
|
||||
menu(const int& _x, const int& _y, const int& _rW, const int& _fS, const int& _mL);
|
||||
void editParam(int _param, int newVal);
|
||||
|
||||
//Gets executed when menu changes at all
|
||||
void setOnChangeFunc(funcPtr func) { onChange = func; }
|
||||
|
||||
//executed when .update() is called.
|
||||
void setCallback(funcPtr _callback, void *args) { callback = _callback; callbackArgs = args; }
|
||||
|
||||
//Adds option.
|
||||
int addOpt(SDL_Texture *_icn, const std::string& add);
|
||||
|
||||
//Adds an function to be executed on pressing button specified
|
||||
void optAddButtonEvent(unsigned _ind, HidNpadButton _button, funcPtr _func, void *args);
|
||||
//Changes opt text
|
||||
void editOpt(int ind, SDL_Texture *_icn, const std::string& ch);
|
||||
size_t getOptCount() { return opt.size(); }
|
||||
int getOptPos(const std::string& txt);
|
||||
|
||||
//Clears menu stuff
|
||||
~menu();
|
||||
|
||||
//Handles controller input and executes functions for buttons if they're set
|
||||
void update();
|
||||
|
||||
//Returns selected option
|
||||
int getSelected() { return selected; }
|
||||
|
||||
//Returns menu option count
|
||||
int getCount() { return opt.size(); }
|
||||
|
||||
//Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected
|
||||
void draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText);
|
||||
|
||||
//Clears and resets menu
|
||||
void reset();
|
||||
|
||||
//Resets selected + start
|
||||
void resetSel() { selected = 0; }
|
||||
|
||||
//Enables control/disables drawing select box
|
||||
void setActive(bool _set);
|
||||
bool getActive() { return isActive; }
|
||||
|
||||
private:
|
||||
//drawing x and y + rectangle width/height. Height is calc'd with font size
|
||||
int x = 0, mY = 0, tY = 0, y = 0, rW = 0, rY = 0, fSize = 0, rH = 0, mL = 0;
|
||||
//Options vector
|
||||
std::vector<ui::menuOpt> opt;
|
||||
//Selected + frame counting for auto-scroll. Hover count is to not break autoscroll
|
||||
int selected = 0, fc = 0, hoverCount = 0, spcWidth = 0;
|
||||
//How much we shift the color of the rectangle
|
||||
uint8_t clrSh = 0;
|
||||
bool clrAdd = true, isActive = true, hover = false;
|
||||
//Option buffer. Basically, text is draw to this so it can't overlap. Also allows scrolling
|
||||
SDL_Texture *optTex;
|
||||
funcPtr onChange = NULL, callback = NULL;
|
||||
void *callbackArgs, *funcArgs;
|
||||
};
|
||||
|
||||
//Progress bar for showing loading. Mostly so people know it didn't freeze
|
||||
class progBar
|
||||
{
|
||||
public:
|
||||
//Constructor. _max is the maximum value
|
||||
progBar() = default;
|
||||
progBar(const uint64_t& _max) { max = _max; }
|
||||
|
||||
void setMax(const uint64_t& _max) { max = _max; };
|
||||
|
||||
//Updates progress
|
||||
void update(const uint64_t& _prog);
|
||||
|
||||
//Draws with text at top
|
||||
void draw(const std::string& text);
|
||||
|
||||
private:
|
||||
uint64_t max = 0, prog = 0;
|
||||
float width = 0;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
std::string message;
|
||||
int rectWidth = 0, frames = 0, y = 720;
|
||||
} popMessage;
|
||||
|
||||
class popMessageMngr
|
||||
{
|
||||
public:
|
||||
~popMessageMngr();
|
||||
|
||||
void update();
|
||||
|
||||
void popMessageAdd(const std::string& mess, int frameTime);
|
||||
void draw();
|
||||
|
||||
private:
|
||||
std::vector<popMessage> popQueue;//All graphics need to be on main thread. Directly adding will cause text issues
|
||||
std::vector<popMessage> message;
|
||||
};
|
||||
|
||||
//General use
|
||||
ui::confirmArgs *confirmArgsCreate(bool _hold, funcPtr _confFunc, funcPtr _cancelFunc, void *_funcArgs, const char *fmt, ...);
|
||||
void confirm(void *a);
|
||||
void showMessage(const char *fmt, ...);
|
||||
bool confirmTransfer(const std::string& f, const std::string& t);
|
||||
bool confirmDelete(const std::string& p);
|
||||
void drawBoundBox(SDL_Texture *target, int x, int y, int w, int h, uint8_t clrSh);
|
||||
void drawTextbox(SDL_Texture *target, int x, int y, int w, int h);
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
void settInit();
|
||||
void settExit();
|
||||
void settUpdate();
|
||||
void settDraw(SDL_Texture *target);
|
||||
|
||||
extern ui::menu *settMenu;
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace ui
|
||||
{
|
||||
//Maybe more later *if* needed, but not now.
|
||||
typedef enum
|
||||
{
|
||||
SLD_LEFT,
|
||||
SLD_RIGHT
|
||||
} slidePanelOrientation;
|
||||
|
||||
//_draw is called and passed the panel texture/target when this.draw() is called.
|
||||
class slideOutPanel
|
||||
{
|
||||
public:
|
||||
slideOutPanel(int _w, int _h, int _y, slidePanelOrientation _side, funcPtr _draw);
|
||||
|
||||
void resizePanel(int _w, int _h, int _y);
|
||||
void update();
|
||||
void setCallback(funcPtr _cb, void *_args) { callback = _cb; cbArgs = _args; }
|
||||
void openPanel() { open = true; }
|
||||
void closePanel() { open = false; }
|
||||
void setX(int _nX){ x = _nX; };
|
||||
bool isOpen() { return open; }
|
||||
void draw(const SDL_Color *backCol);
|
||||
|
||||
private:
|
||||
int w, h, x, y;
|
||||
uint8_t sldSide;
|
||||
bool open = false;
|
||||
SDL_Texture *panel;
|
||||
funcPtr drawFunc, callback = NULL;
|
||||
void *cbArgs = NULL;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "type.h"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class threadProcMngr
|
||||
{
|
||||
public:
|
||||
~threadProcMngr();
|
||||
//Draw function is used and called to draw on overlay
|
||||
threadInfo *newThread(ThreadFunc func, void *args, funcPtr _drawFunc);
|
||||
void update();
|
||||
void draw();
|
||||
bool empty() { return threads.empty(); }
|
||||
|
||||
private:
|
||||
std::vector<threadInfo *> threads;
|
||||
uint8_t lgFrame = 0, clrShft = 0;
|
||||
bool clrAdd = true;
|
||||
unsigned frameCount = 0;
|
||||
Mutex threadLock = 0;
|
||||
};
|
||||
}
|
||||
17
inc/ui/ttl.h
17
inc/ui/ttl.h
|
|
@ -1,17 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace ui
|
||||
{
|
||||
void ttlInit();
|
||||
void ttlExit();
|
||||
void ttlSetActive(int usr, bool _set, bool _showSel);
|
||||
void ttlRefresh();
|
||||
|
||||
//JIC for func ptr
|
||||
void ttlReset();
|
||||
void ttlUpdate();
|
||||
void ttlDraw(SDL_Texture *target);
|
||||
|
||||
//File mode needs access to this.
|
||||
extern ui::slideOutPanel *ttlOptsPanel;
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include "type.h"
|
||||
#include "data.h"
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class titleTile
|
||||
{
|
||||
public:
|
||||
titleTile(unsigned _w, unsigned _h, bool _fav, SDL_Texture *_icon)
|
||||
{
|
||||
w = _w;
|
||||
h = _h;
|
||||
wS = _w;
|
||||
hS = _h;
|
||||
fav = _fav;
|
||||
icon = _icon;
|
||||
}
|
||||
|
||||
void draw(SDL_Texture *target, int x, int y, bool sel);
|
||||
|
||||
private:
|
||||
unsigned w, h, wS, hS;
|
||||
bool fav = false;
|
||||
SDL_Texture *icon;
|
||||
};
|
||||
|
||||
//Todo less hardcode etc
|
||||
class titleview
|
||||
{
|
||||
public:
|
||||
titleview(const data::user& _u, int _iconW, int _iconH, int _horGap, int _vertGap, int _rowCount, funcPtr _callback);
|
||||
~titleview();
|
||||
|
||||
void update();
|
||||
void refresh();
|
||||
|
||||
void setActive(bool _set, bool _showSel) { active = _set; showSel = _showSel; }
|
||||
bool getActive() { return active; }
|
||||
void setSelected(int _set) { selected = _set; }
|
||||
int getSelected() { return selected; }
|
||||
void draw(SDL_Texture *target);
|
||||
|
||||
private:
|
||||
const data::user *u;//Might not be safe. Users *shouldn't* be touched after initial load
|
||||
bool active = false, showSel = false, clrAdd = true;
|
||||
uint8_t clrShft = 0;
|
||||
funcPtr callback = NULL;
|
||||
int x = 200, y = 62, selected = 0, selRectX = 10, selRectY = 45;
|
||||
int iconW, iconH, horGap, vertGap, rowCount;
|
||||
std::vector<ui::titleTile *> tiles;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
//Strings since translation support
|
||||
namespace ui
|
||||
{
|
||||
void initStrings();
|
||||
void loadTrans();
|
||||
void saveTranslationFiles(void *a);
|
||||
extern std::map<std::pair<std::string, int>, std::string> strings;
|
||||
|
||||
inline std::string getUIString(const std::string& _name, int ind){ return strings[std::make_pair(_name, ind)]; }
|
||||
inline const char *getUICString(const std::string& _name, int ind){ return strings[std::make_pair(_name, ind)].c_str(); }
|
||||
}
|
||||
14
inc/ui/usr.h
14
inc/ui/usr.h
|
|
@ -1,14 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace ui
|
||||
{
|
||||
void usrInit();
|
||||
void usrExit();
|
||||
void usrRefresh();
|
||||
void usrUpdate();
|
||||
void usrDraw(SDL_Texture *target);
|
||||
|
||||
//A lot of stuff needs access to these
|
||||
extern ui::menu *usrMenu;
|
||||
extern ui::slideOutPanel *usrSelPanel;
|
||||
}
|
||||
158
inc/util.h
158
inc/util.h
|
|
@ -1,158 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "data.h"
|
||||
#include "ui.h"
|
||||
#include "file.h"
|
||||
#include "gfx.h"
|
||||
|
||||
namespace util
|
||||
{
|
||||
enum
|
||||
{
|
||||
DATE_FMT_YMD,
|
||||
DATE_FMT_YDM,
|
||||
DATE_FMT_HOYSTE,
|
||||
DATE_FMT_JHK,
|
||||
DATE_FMT_ASC
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CPU_SPEED_204MHz = 204000000,
|
||||
CPU_SPEED_306MHz = 306000000,
|
||||
CPU_SPEED_408MHz = 408000000,
|
||||
CPU_SPEED_510MHz = 510000000,
|
||||
CPU_SPEED_612MHz = 612000000,
|
||||
CPU_SPEED_714MHz = 714000000,
|
||||
CPU_SPEED_816MHz = 816000000,
|
||||
CPU_SPEED_918MHz = 918000000,
|
||||
CPU_SPEED_1020MHz = 1020000000, //Default
|
||||
CPU_SPEED_1122MHz = 1122000000,
|
||||
CPU_SPEED_1224MHz = 1224000000,
|
||||
CPU_SPEED_1326MHz = 1326000000,
|
||||
CPU_SPEED_1428MHz = 1428000000,
|
||||
CPU_SPEED_1581MHz = 1581000000,
|
||||
CPU_SPEED_1683MHz = 1683000000,
|
||||
CPU_SPEED_1785MHz = 1785000000
|
||||
} cpuSpds;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GPU_SPEED_0MHz = 0,
|
||||
GPU_SPEED_76MHz = 76800000,
|
||||
GPU_SPEED_153MHz = 153600000,
|
||||
GPU_SPEED_203MHz = 230400000,
|
||||
GPU_SPEED_307MHz = 307200000, //Handheld 1
|
||||
GPU_SPEED_384MHz = 384000000, //Handheld 2
|
||||
GPU_SPEED_460MHz = 460800000,
|
||||
GPU_SPEED_537MHz = 537600000,
|
||||
GPU_SPEED_614MHz = 614400000,
|
||||
GPU_SPEED_768MHz = 768000000, //Docked
|
||||
GPU_SPEED_844MHz = 844800000,
|
||||
GPU_SPEED_921MHZ = 921600000
|
||||
} gpuSpds;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RAM_SPEED_0MHz = 0,
|
||||
RAM_SPEED_40MHz = 40800000,
|
||||
RAM_SPEED_68MHz = 68000000,
|
||||
RAM_SPEED_102MHz = 102000000,
|
||||
RAM_SPEED_204MHz = 204000000,
|
||||
RAM_SPEED_408MHz = 408000000,
|
||||
RAM_SPEED_665MHz = 665600000,
|
||||
RAM_SPEED_800MHz = 800000000,
|
||||
RAM_SPEED_1065MHz = 1065600000,
|
||||
RAM_SPEED_1331MHz = 1331200000,
|
||||
RAM_SPEED_1600MHz = 1600000000
|
||||
} ramSpds;
|
||||
|
||||
//Returns string with date S+ time
|
||||
std::string getDateTime(int fmt);
|
||||
|
||||
//Copys dir list to a menu with 'D: ' + 'F: '
|
||||
void copyDirListToMenu(const fs::dirList& d, ui::menu& m);
|
||||
|
||||
//Removes last folder from '_path'
|
||||
void removeLastFolderFromString(std::string& _path);
|
||||
size_t getTotalPlacesInPath(const std::string& _path);
|
||||
void trimPath(std::string& _path, uint8_t _places);
|
||||
|
||||
inline bool isASCII(const uint32_t& t)
|
||||
{
|
||||
return t > 30 && t < 127;
|
||||
}
|
||||
|
||||
std::string safeString(const std::string& s);
|
||||
|
||||
std::string getStringInput(SwkbdType _type, const std::string& def, const std::string& head, size_t maxLength, unsigned dictCnt, const std::string dictWords[]);
|
||||
|
||||
std::string getExtensionFromString(const std::string& get);
|
||||
std::string getFilenameFromPath(const std::string& get);
|
||||
|
||||
std::string generateAbbrev(const uint64_t& tid);
|
||||
|
||||
//removes char from C++ string
|
||||
void stripChar(char _c, std::string& _s);
|
||||
|
||||
void replaceStr(std::string& _str, const std::string& _find, const std::string& _rep);
|
||||
|
||||
//For future external translation support. Replaces [button] with button chars
|
||||
void replaceButtonsInString(std::string& rep);
|
||||
|
||||
//Creates a basic generic icon for stuff without one
|
||||
SDL_Texture *createIconGeneric(const char *txt, int fontSize, bool clearBack);
|
||||
|
||||
inline u128 accountUIDToU128(AccountUid uid)
|
||||
{
|
||||
return ((u128)uid.uid[0] << 64 | uid.uid[1]);
|
||||
}
|
||||
|
||||
inline AccountUid u128ToAccountUID(u128 id)
|
||||
{
|
||||
AccountUid ret;
|
||||
ret.uid[0] = id >> 64;
|
||||
ret.uid[1] = id;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline std::string getIDStr(const uint64_t& _id)
|
||||
{
|
||||
char tmp[18];
|
||||
sprintf(tmp, "%016lX", _id);
|
||||
return std::string(tmp);
|
||||
}
|
||||
|
||||
inline std::string getIDStrLower(const uint64_t& _id)
|
||||
{
|
||||
char tmp[18];
|
||||
sprintf(tmp, "%08X", (uint32_t)_id);
|
||||
return std::string(tmp);
|
||||
}
|
||||
|
||||
inline std::string generatePathByTID(const uint64_t& tid)
|
||||
{
|
||||
return fs::getWorkDir() + data::getTitleSafeNameByTID(tid) + "/";
|
||||
}
|
||||
|
||||
std::string getSizeString(const uint64_t& _size);
|
||||
|
||||
inline void createTitleDirectoryByTID(const uint64_t& tid)
|
||||
{
|
||||
std::string makePath = fs::getWorkDir() + data::getTitleSafeNameByTID(tid);
|
||||
mkdir(makePath.c_str(), 777);
|
||||
}
|
||||
|
||||
Result accountDeleteUser(AccountUid *uid);
|
||||
|
||||
void sysBoost();
|
||||
void sysNormal();
|
||||
|
||||
inline bool isApplet()
|
||||
{
|
||||
AppletType type = appletGetAppletType();
|
||||
return type == AppletType_LibraryApplet;
|
||||
}
|
||||
|
||||
void checkForUpdate(void *a);
|
||||
}
|
||||
53
inc/webdav.h
53
inc/webdav.h
|
|
@ -1,53 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <string>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include "rfs.h"
|
||||
|
||||
namespace rfs {
|
||||
|
||||
// Note: Everything declared an "id" is the full path component from the origin to the resource starting with a "/".
|
||||
// Note: Directories ALWAYS have a trailing / while files NEVER have a trailing /
|
||||
// e.g. /<basePath>/JKSV/
|
||||
// e.g. /<basePath>/JKSV/<title-id>/
|
||||
// e.g. /<basePath>/JKSV/<title-id>/<file>
|
||||
// e.g. /
|
||||
// other string arguments never have any leading or trailing "/"
|
||||
class WebDav : public IRemoteFS {
|
||||
private:
|
||||
CURL* curl;
|
||||
std::string origin;
|
||||
std::string basePath;
|
||||
std::string username;
|
||||
std::string password;
|
||||
|
||||
|
||||
std::vector<RfsItem> parseXMLResponse(const std::string& xml);
|
||||
bool resourceExists(const std::string& id);
|
||||
std::string appendResourceToParentId(const std::string& resourceName, const std::string& parentId, bool isDir);
|
||||
std::string getNamespacePrefix(tinyxml2::XMLElement* root, const std::string& nsURI);
|
||||
|
||||
public:
|
||||
WebDav(const std::string& origin,
|
||||
const std::string& username,
|
||||
const std::string& password);
|
||||
~WebDav();
|
||||
|
||||
bool createDir(const std::string& dirName, const std::string& parentId);
|
||||
bool dirExists(const std::string& dirName, const std::string& parentId);
|
||||
|
||||
bool fileExists(const std::string& filename, const std::string& parentId);
|
||||
void uploadFile(const std::string& filename, const std::string& parentId, curlFuncs::curlUpArgs *_upload);
|
||||
void updateFile(const std::string& fileID, curlFuncs::curlUpArgs *_upload);
|
||||
void downloadFile(const std::string& fileID, curlFuncs::curlDlArgs *_download);
|
||||
void deleteFile(const std::string& fileID);
|
||||
|
||||
std::string getFileID(const std::string& name, const std::string& parentId);
|
||||
std::string getDirID(const std::string& dirName, const std::string& parentId);
|
||||
|
||||
std::vector<RfsItem> getListWithParent(const std::string& _parent);
|
||||
std::string getDisplayNameFromURL(const std::string &url);
|
||||
};
|
||||
}
|
||||
61
include/JKSV.hpp
Normal file
61
include/JKSV.hpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "sdl.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
/// @brief Main application class.
|
||||
class JKSV
|
||||
{
|
||||
public:
|
||||
/// @brief Initializes JKSV. Initializes services.
|
||||
JKSV();
|
||||
|
||||
/// @brief Exits services.
|
||||
~JKSV();
|
||||
|
||||
/// @brief Returns if initializing was successful and JKSV is running.
|
||||
/// @return True or false.
|
||||
bool is_running() const noexcept;
|
||||
|
||||
/// @brief Runs JKSV's update routine.
|
||||
void update();
|
||||
|
||||
/// @brief Runs JKSV's render routine.
|
||||
void render();
|
||||
|
||||
private:
|
||||
/// @brief Whether or not initialization was successful and JKSV is still running.
|
||||
bool m_isRunning{};
|
||||
|
||||
/// @brief Whether or not to print the translation credits.
|
||||
bool m_showTranslationInfo{};
|
||||
|
||||
/// @brief JKSV icon in upper left corner.
|
||||
sdl::SharedTexture m_headerIcon{};
|
||||
|
||||
/// @brief Stores the translation string.
|
||||
std::string m_translationInfo{};
|
||||
|
||||
/// @brief Stores the build string.
|
||||
std::string m_buildString{};
|
||||
|
||||
/// @brief Initializes fslib and takes care of a few other things.
|
||||
bool initialize_filesystem();
|
||||
|
||||
/// @brief Initializes the services JKSV uses.
|
||||
bool initialize_services();
|
||||
|
||||
/// @brief Initializes SDL and loads the header icon.
|
||||
bool initialize_sdl();
|
||||
|
||||
// Creates the needed directories on SD.
|
||||
bool create_directories();
|
||||
|
||||
/// @brief Adds the text color changing characters.
|
||||
void add_color_chars();
|
||||
|
||||
/// @brief Exits all services.
|
||||
void exit_services();
|
||||
};
|
||||
52
include/JSON.hpp
Normal file
52
include/JSON.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
#include <json-c/json.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace json
|
||||
{
|
||||
// Use this instead of default json_object
|
||||
using Object = std::unique_ptr<json_object, decltype(&json_object_put)>;
|
||||
|
||||
// Use this instead of json_object_from_x. Pass the function and its arguments instead.
|
||||
template <typename... Args>
|
||||
static inline json::Object new_object(json_object *(*function)(Args...), Args... args)
|
||||
{
|
||||
return json::Object((*function)(args...), json_object_put);
|
||||
}
|
||||
|
||||
/// @brief Inline wrapper function for getting a json object by it's key.
|
||||
/// @param json json::Object to get the key from.
|
||||
/// @param key Key to get.
|
||||
/// @return json_object on success. NULL on failure.
|
||||
static inline json_object *get_object(json::Object &json, std::string_view key)
|
||||
{
|
||||
return json_object_object_get(json.get(), key.data());
|
||||
}
|
||||
|
||||
/// @brief Inline wrapper function to add an object to a json_object
|
||||
/// @param json Json object to add an object to.
|
||||
/// @param key Key of the object.
|
||||
/// @param object Object to add to json.
|
||||
/// @return True on success. False on failure.
|
||||
static inline bool add_object(json::Object &json, std::string_view key, json_object *object)
|
||||
{
|
||||
return json_object_object_add(json.get(), key.data(), object) == 0;
|
||||
}
|
||||
|
||||
/// @brief Returns the json string.
|
||||
static inline const char *get_string(json::Object &json) { return json_object_get_string(json.get()); }
|
||||
|
||||
/// @brief Returns the length of the string. I find json_object_get_string_len is unreliable?
|
||||
static inline int64_t length(json::Object &json)
|
||||
{
|
||||
const char *string = json_object_get_string(json.get());
|
||||
return std::char_traits<char>::length(string);
|
||||
}
|
||||
|
||||
/// @brief Returns the beginning for iterating.
|
||||
static inline json_object_iterator iter_begin(json::Object &json) { return json_object_iter_begin(json.get()); }
|
||||
|
||||
/// @brief Returns the end for iterating.
|
||||
static inline json_object_iterator iter_end(json::Object &json) { return json_object_iter_end(json.get()); }
|
||||
} // namespace json
|
||||
39
include/StateManager.hpp
Normal file
39
include/StateManager.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
#include "appstates/BaseState.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class StateManager
|
||||
{
|
||||
public:
|
||||
// Singleton. No copying or constructing.
|
||||
StateManager(const StateManager &) = delete;
|
||||
StateManager(StateManager &&) = delete;
|
||||
StateManager &operator=(const StateManager &) = delete;
|
||||
StateManager &operator=(StateManager &&) = delete;
|
||||
|
||||
/// @brief Runs the state update routine.
|
||||
static void update();
|
||||
|
||||
/// @brief Runs the state rendering routine(s);
|
||||
static void render() noexcept;
|
||||
|
||||
/// @brief Returns whether the back of the vector is a closable state.
|
||||
static bool back_is_closable() noexcept;
|
||||
|
||||
/// @brief Pushes a new state to the state vector.
|
||||
/// @param newState Shared_ptr to state to push.
|
||||
static void push_state(std::shared_ptr<BaseState> newState);
|
||||
|
||||
private:
|
||||
/// @brief Private constructor so no constructing.
|
||||
StateManager() = default;
|
||||
|
||||
/// @brief Returns a reference to the instance of StateManger.
|
||||
/// @return Reference to state manager.
|
||||
static StateManager &get_instance();
|
||||
|
||||
/// @brief This is the vector that holds the pointers to the states.
|
||||
std::vector<std::shared_ptr<BaseState>> m_stateVector;
|
||||
};
|
||||
170
include/appstates/BackupMenuState.hpp
Normal file
170
include/appstates/BackupMenuState.hpp
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
/// @brief This is the state where the user can backup and restore saves.
|
||||
class BackupMenuState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Creates a new backup selection state.
|
||||
/// @param user Pointer to currently selected user.
|
||||
/// @param titleInfo Pointer to titleInfo of selected title.
|
||||
/// @param saveType Save data type we're working with.
|
||||
BackupMenuState(data::User *user, data::TitleInfo *titleInfo);
|
||||
|
||||
/// @brief Creates and returns a new BackupMenuState.
|
||||
static inline std::shared_ptr<BackupMenuState> create(data::User *user, data::TitleInfo *titleInfo)
|
||||
{
|
||||
return std::make_shared<BackupMenuState>(user, titleInfo);
|
||||
}
|
||||
|
||||
/// @brief Creates and pushes a new BackupMenuState to the vector.
|
||||
static inline std::shared_ptr<BackupMenuState> create_and_push(data::User *user, data::TitleInfo *titleInfo)
|
||||
{
|
||||
auto newState = BackupMenuState::create(user, titleInfo);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Required. Inherited virtual function from AppState.
|
||||
void update() override;
|
||||
|
||||
/// @brief Required. Inherited virtual function from AppState.
|
||||
void render() override;
|
||||
|
||||
/// @brief Refreshes the directory listing and menu.
|
||||
void refresh();
|
||||
|
||||
/// @brief Allows a spawned task to tell this class that it wrote save data to the system.
|
||||
void save_data_written();
|
||||
|
||||
// clang-format off
|
||||
enum class MenuEntryType
|
||||
{
|
||||
Null,
|
||||
Local,
|
||||
Remote
|
||||
};
|
||||
|
||||
struct MenuEntry
|
||||
{
|
||||
MenuEntryType type{};
|
||||
int index{};
|
||||
};
|
||||
|
||||
struct DataStruct
|
||||
{
|
||||
data::User *user{};
|
||||
data::TitleInfo *titleInfo{};
|
||||
fslib::Path path{}; // This and
|
||||
remote::Item *remoteItem{}; // this are set when needed.
|
||||
BackupMenuState *spawningState{};
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// This makes some things elsewhere easier to type.
|
||||
using TaskData = std::shared_ptr<BackupMenuState::DataStruct>;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to current user.
|
||||
data::User *m_user{};
|
||||
|
||||
/// @brief Pointer to data for selected title.
|
||||
data::TitleInfo *m_titleInfo{};
|
||||
|
||||
/// @brief Save data type we're working with.
|
||||
FsSaveDataType m_saveType{};
|
||||
|
||||
/// @brief Path to the target directory of the title.
|
||||
fslib::Path m_directoryPath{};
|
||||
|
||||
/// @brief Directory listing of the above.
|
||||
fslib::Directory m_directoryListing{};
|
||||
|
||||
/// @brief Remote storage listing of the current parent.
|
||||
remote::Storage::DirectoryListing m_remoteListing{};
|
||||
|
||||
/// @brief This is the scrolling text at the top.
|
||||
std::shared_ptr<ui::TextScroll> m_titleScroll{};
|
||||
|
||||
/// @brief Variable that saves whether or not the filesystem has data in it.
|
||||
bool m_saveHasData{};
|
||||
|
||||
/// @brief Data struct passed to functions.
|
||||
std::shared_ptr<BackupMenuState::DataStruct> m_dataStruct{};
|
||||
|
||||
/// @brief This keeps track of the properties of the entries in the menu.
|
||||
std::vector<BackupMenuState::MenuEntry> m_menuEntries{};
|
||||
|
||||
/// @brief This is a pointer to the control guide string.
|
||||
const char *m_controlGuide{};
|
||||
|
||||
/// @brief The width of the panels. This is set according to the control guide text.
|
||||
static inline int sm_panelWidth{};
|
||||
|
||||
/// @brief The menu used by all instances of BackupMenuState.
|
||||
static inline std::shared_ptr<ui::Menu> sm_backupMenu{};
|
||||
|
||||
/// @brief Prevents this and threads calling refresh() from causing races.
|
||||
static inline std::mutex sm_menuMutex{};
|
||||
|
||||
/// @brief The slide out panel used by all instances of BackupMenuState.
|
||||
static inline std::shared_ptr<ui::SlideOutPanel> sm_slidePanel{};
|
||||
|
||||
/// @brief Inner render target so the menu only renders to a certain area.
|
||||
static inline sdl::SharedTexture sm_menuRenderTarget{};
|
||||
|
||||
/// @brief Initializes the static members all instances share if they haven't been already.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Checks for and tries to create the target directory if it hasn't been already.
|
||||
void ensure_target_directory();
|
||||
|
||||
/// @brief Initializes the struct passed to tasks.
|
||||
void initialize_task_data();
|
||||
|
||||
/// @brief Init's the string at the top of the backupmenu.
|
||||
void initialize_info_string();
|
||||
|
||||
/// @brief Checks to see if the save data is empty.
|
||||
void save_data_check();
|
||||
|
||||
/// @brief Ensures the remote storage is initalized and pointing to the right place.
|
||||
void initialize_remote_storage();
|
||||
|
||||
/// @brief This is the function called when New Backup is selected.
|
||||
void name_and_create_backup();
|
||||
|
||||
/// @brief This is the function called when a backup is selected to be overwritten.
|
||||
void confirm_overwrite();
|
||||
|
||||
/// @brief This function is called to confirm restoring a backup.
|
||||
void confirm_restore();
|
||||
|
||||
/// @brief Function called to confirm deleting a backup.
|
||||
void confirm_delete();
|
||||
|
||||
/// @brief Uploads the currently selected backup to the remote storage.
|
||||
void upload_backup();
|
||||
|
||||
/// @brief Just creates the pop-up that says Save is empty or w/e.
|
||||
void pop_save_empty();
|
||||
|
||||
/// @brief Performs some operations and then marks the state for purging.
|
||||
void deactivate_state();
|
||||
|
||||
inline bool user_is_system()
|
||||
{
|
||||
const uint8_t saveType = m_user->get_account_save_type();
|
||||
return saveType == FsSaveDataType_System || saveType == FsSaveDataType_SystemBcat;
|
||||
}
|
||||
};
|
||||
58
include/appstates/BaseState.hpp
Normal file
58
include/appstates/BaseState.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
#include "sdl.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Base application state class.
|
||||
/// @param isClosable Optional. Controls whether or not the state should allow JKSV to close.
|
||||
BaseState(bool isClosable = true);
|
||||
|
||||
/// @brief Ends homebutton and plus locking.
|
||||
virtual ~BaseState();
|
||||
|
||||
/// @brief Every derived class is required to have this function.
|
||||
virtual void update() = 0;
|
||||
|
||||
/// @brief Sub update routine. Meant to handle minor background tasks. Not meant for full update routines.
|
||||
virtual void sub_update() {};
|
||||
|
||||
/// @brief Every derived class is required to have this function.
|
||||
virtual void render() = 0;
|
||||
|
||||
/// @brief Deactivates state and allows JKSV to purge it from the vector.
|
||||
void deactivate();
|
||||
|
||||
/// @brief Allows a state to be reactivated and pushed to the vector.
|
||||
void reactivate();
|
||||
|
||||
/// @brief Returns if the state is still active.
|
||||
/// @return Whether state is still active or can be purged.
|
||||
bool is_active() const;
|
||||
|
||||
/// @brief Tells the state it's at the back of the vector and has focus.
|
||||
void give_focus();
|
||||
|
||||
/// @brief Takes the focus away and tells the state it's no long back();
|
||||
void take_focus();
|
||||
|
||||
/// @brief Allows the state to know whether it has focus.
|
||||
/// @return Whether state has focus or not.
|
||||
bool has_focus() const;
|
||||
|
||||
/// @brief Returns whether or not JKSV should allow closing while state is active.
|
||||
/// @return True if closable. False if not.
|
||||
bool is_closable() const;
|
||||
|
||||
private:
|
||||
/// @brief Stores whether or not the state is currently active.
|
||||
bool m_isActive{true};
|
||||
|
||||
/// @brief Stores whether or not the state has focus.
|
||||
bool m_hasFocus{};
|
||||
|
||||
/// @brief Stores whether or not the state allows closing.
|
||||
bool m_isClosable{};
|
||||
};
|
||||
56
include/appstates/BaseTask.hpp
Normal file
56
include/appstates/BaseTask.hpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#pragma once
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
#include "ui/ColorMod.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
/// @brief Normally, I wouldn't do this, but this holds a single function both TaskState and ProgressState share...
|
||||
class BaseTask : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructor. Starts the glyph timer and sets AppState to not allow closing.
|
||||
BaseTask();
|
||||
|
||||
/// @brief Runs the update routine for rendering the loading glyph animation.
|
||||
/// @param
|
||||
virtual void update() = 0;
|
||||
|
||||
/// @brief Virtual render function.
|
||||
virtual void render() = 0;
|
||||
|
||||
protected:
|
||||
/// @brief Underlying system task. This needs to be allocated by the derived classes.
|
||||
std::unique_ptr<sys::Task> m_task{};
|
||||
|
||||
/// @brief Updates the loading glyph animation.
|
||||
void update_loading_glyph();
|
||||
|
||||
/// @brief Displays the "can't quit JKSV" when plus is pressed.
|
||||
void pop_on_plus();
|
||||
|
||||
/// @brief This function renders the loading glyph in the bottom left corner.
|
||||
/// @note This is mostly just so users don't think JKSV has frozen when operations take a long time.
|
||||
void render_loading_glyph();
|
||||
|
||||
/// @brief This is the font size used for displaying text during tasks.
|
||||
static inline constexpr int FONT_SIZE = 20;
|
||||
|
||||
private:
|
||||
/// @brief This is the current frame of the loading glyph animation.
|
||||
int m_currentFrame{};
|
||||
|
||||
/// @brief This is the timer used for changing the current glyph/frame of the animation.
|
||||
sys::Timer m_frameTimer{};
|
||||
|
||||
/// @brief This is used to give the animation its pulsing color.
|
||||
ui::ColorMod m_colorMod{};
|
||||
|
||||
/// @brief This is a pointer to the string popped when plus is pressed.
|
||||
const char *m_popUnableExit{};
|
||||
|
||||
/// @brief This array holds the glyphs of the loading sequence. I think it's from the Wii?
|
||||
static inline constexpr std::array<std::string_view, 8> sm_glyphArray =
|
||||
{"\ue020", "\ue021", "\ue022", "\ue023", "\ue024", "\ue025", "\ue026", "\ue027"};
|
||||
};
|
||||
59
include/appstates/BlacklistEditState.hpp
Normal file
59
include/appstates/BlacklistEditState.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class BlacklistEditState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructor. Loads the blacklist and ensures the panel is allocated.S
|
||||
BlacklistEditState();
|
||||
|
||||
/// @brief Creates and returns a new state.
|
||||
static inline std::shared_ptr<BlacklistEditState> create() { return std::make_shared<BlacklistEditState>(); }
|
||||
|
||||
/// @brief Creates, pushes, then returns a new blacklist edit states.
|
||||
static inline std::shared_ptr<BlacklistEditState> create_and_push()
|
||||
{
|
||||
auto newState = BlacklistEditState::create();
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Update override.
|
||||
void update() override;
|
||||
|
||||
/// @brief Render override.
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Local copy of the blacklist.
|
||||
std::vector<uint64_t> m_blacklist{};
|
||||
|
||||
/// @brief Menu with blacklisted titles.
|
||||
std::shared_ptr<ui::Menu> m_blacklistMenu{};
|
||||
|
||||
/// @brief This panel is shared by all instances.
|
||||
static inline std::unique_ptr<ui::SlideOutPanel> sm_slidePanel{};
|
||||
|
||||
/// @brief Inits ^.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Loads the blacklist from config.
|
||||
void load_blacklist();
|
||||
|
||||
/// @brief Fills the menu with the titles blacklisted.
|
||||
void initialize_menu();
|
||||
|
||||
/// @brief Updates the menu.
|
||||
void refresh_menu();
|
||||
|
||||
/// @brief Removes the selected title from the blacklist and refreshes everything.
|
||||
void remove_from_blacklist();
|
||||
|
||||
/// @brief Performs some operations and marks the state for purging.
|
||||
void deactivate_state();
|
||||
};
|
||||
231
include/appstates/ConfirmState.hpp
Normal file
231
include/appstates/ConfirmState.hpp
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "appstates/FadeState.hpp"
|
||||
#include "appstates/ProgressState.hpp"
|
||||
#include "appstates/TaskState.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logging/logger.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "strings/strings.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
// This is the base position on the screen used to center the Yes [A](...) text.
|
||||
constexpr int COORD_YES_X = 460;
|
||||
// ^ but for no.
|
||||
constexpr int COORD_NO_X = 820;
|
||||
} // namespace
|
||||
|
||||
/// @brief Templated class to create confirmation dialogs.
|
||||
/// @tparam TaskType The type of task spawned on confirmation. Ex: Task, ProgressTask
|
||||
/// @tparam StateType The state type spawned on confirmation. Ex: TaskState, ProgressState
|
||||
/// @tparam StructType The type of struct passed to the state on confirmation.
|
||||
template <typename TaskType, typename StateType, typename StructType>
|
||||
class ConfirmState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief All functions passed to this state need to follow this signature: void function(<TaskType> *,
|
||||
/// std::shared_ptr<<StructType>>)
|
||||
using TaskFunction = void (*)(TaskType *, std::shared_ptr<StructType>);
|
||||
|
||||
/// @brief Constructor for new ConfirmState.
|
||||
/// @param query The string displayed.
|
||||
/// @param holdRequired Whether or not confirmation requires holding A for three seconds.
|
||||
/// @param function Function executed on confirmation.
|
||||
/// @param dataStruct shared_ptr<StructType> that is passed to function. I tried templating this and it was a nightmare.
|
||||
ConfirmState(std::string_view query, bool holdRequired, TaskFunction function, std::shared_ptr<StructType> dataStruct)
|
||||
: BaseState(false)
|
||||
, m_query(query)
|
||||
, m_yesText(strings::get_by_name(strings::names::YES_NO_OK, 0))
|
||||
, m_noText(strings::get_by_name(strings::names::YES_NO_OK, 1))
|
||||
, m_holdRequired(holdRequired)
|
||||
, m_function(function)
|
||||
, m_dataStruct(dataStruct)
|
||||
{
|
||||
ConfirmState::initialize_static_members();
|
||||
ConfirmState::center_no();
|
||||
ConfirmState::center_yes();
|
||||
ConfirmState::load_holding_strings();
|
||||
}
|
||||
|
||||
/// @brief Returns a new ConfirmState. See constructor.
|
||||
static inline std::shared_ptr<ConfirmState> create(std::string_view query,
|
||||
bool holdRequired,
|
||||
TaskFunction function,
|
||||
std::shared_ptr<StructType> dataStruct)
|
||||
{
|
||||
return std::make_shared<ConfirmState>(query, holdRequired, function, dataStruct);
|
||||
}
|
||||
|
||||
/// @brief Creates and returns a new ConfirmState and pushes it.
|
||||
static inline std::shared_ptr<ConfirmState> create_and_push(std::string_view query,
|
||||
bool holdRequired,
|
||||
TaskFunction function,
|
||||
std::shared_ptr<StructType> dataStruct)
|
||||
{
|
||||
// I'm gonna use a sneaky trick here. This shouldn't do this because it's confusing.
|
||||
auto newState = create(query, holdRequired, function, dataStruct);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Same as above but with a fade transition pushed in between.
|
||||
static std::shared_ptr<ConfirmState> create_push_fade(std::string_view query,
|
||||
bool holdRequired,
|
||||
TaskFunction function,
|
||||
std::shared_ptr<StructType> dataStruct)
|
||||
{
|
||||
auto newState = ConfirmState::create(query, holdRequired, function, dataStruct);
|
||||
FadeState::create_and_push(colors::DIM_BACKGROUND, 0x00, 0x88, newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Just updates the ConfirmState.
|
||||
void update() override
|
||||
{
|
||||
const bool aPressed = input::button_pressed(HidNpadButton_A);
|
||||
const bool bPressed = input::button_pressed(HidNpadButton_B);
|
||||
const bool aHeld = input::button_held(HidNpadButton_A);
|
||||
const bool aReleased = input::button_released(HidNpadButton_A);
|
||||
|
||||
m_triggerGuard = m_triggerGuard || (aPressed && !m_triggerGuard);
|
||||
const bool noHoldTrigger = m_triggerGuard && aPressed && !m_holdRequired;
|
||||
const bool holdTriggered = m_triggerGuard && aPressed && m_holdRequired;
|
||||
const bool holdSustained = m_triggerGuard && aHeld && m_holdRequired;
|
||||
|
||||
if (noHoldTrigger) { ConfirmState::confirmed(); }
|
||||
else if (holdTriggered) { ConfirmState::hold_triggered(); }
|
||||
else if (holdSustained) { ConfirmState::hold_sustained(); }
|
||||
else if (aReleased) { ConfirmState::hold_released(); }
|
||||
else if (bPressed) { ConfirmState::cancelled(); }
|
||||
}
|
||||
|
||||
/// @brief Renders the state to screen.
|
||||
void render() override
|
||||
{
|
||||
const bool hasFocus = BaseState::has_focus();
|
||||
|
||||
sdl::render_rect_fill(sdl::Texture::Null, 0, 0, 1280, 720, colors::DIM_BACKGROUND);
|
||||
|
||||
sm_dialog->render(sdl::Texture::Null, hasFocus);
|
||||
sdl::text::render(sdl::Texture::Null, 312, 288, 20, 656, colors::WHITE, m_query);
|
||||
|
||||
sdl::render_line(sdl::Texture::Null, 280, 454, 999, 454, colors::DIV_COLOR);
|
||||
sdl::render_line(sdl::Texture::Null, 640, 454, 640, 517, colors::DIV_COLOR);
|
||||
|
||||
sdl::text::render(sdl::Texture::Null, m_yesX, 476, 22, sdl::text::NO_WRAP, colors::WHITE, m_yesText);
|
||||
sdl::text::render(sdl::Texture::Null, m_noX, 476, 22, sdl::text::NO_WRAP, colors::WHITE, m_noText);
|
||||
}
|
||||
|
||||
private:
|
||||
/// @brief This stores the query text.
|
||||
std::string m_query{};
|
||||
|
||||
/// @brief These are pointers to the strings used to avoid call strings::get_by_name so much.
|
||||
const char *m_yesText{}, *m_noText{};
|
||||
|
||||
/// @brief X coordinate to render the Yes No
|
||||
int m_yesX{}, m_noX{};
|
||||
|
||||
/// @brief This is to prevent the dialog from triggering immediately.
|
||||
bool m_triggerGuard{};
|
||||
|
||||
/// @brief Whether or not holding [A] to confirm is required.
|
||||
const bool m_holdRequired{};
|
||||
|
||||
/// @brief These are pointers to the holding strings.
|
||||
const char *m_holdText[3]{};
|
||||
|
||||
/// @brief Keep track of the ticks/time needed to confirm.
|
||||
uint64_t m_startingTickCount{};
|
||||
|
||||
/// @brief Keeps track of which
|
||||
int m_stage{};
|
||||
|
||||
/// @brief Function to execute if action is confirmed.
|
||||
const TaskFunction m_function{};
|
||||
|
||||
/// @brief Pointer to data struct passed to ^
|
||||
const std::shared_ptr<StructType> m_dataStruct{};
|
||||
|
||||
static inline std::shared_ptr<ui::DialogBox> sm_dialog{};
|
||||
|
||||
void initialize_static_members()
|
||||
{
|
||||
if (sm_dialog) { return; }
|
||||
|
||||
sm_dialog = ui::DialogBox::create(280, 262, 720, 256);
|
||||
}
|
||||
|
||||
// This just centers the Yes or holding text.
|
||||
void center_yes()
|
||||
{
|
||||
const int yesWidth = sdl::text::get_width(22, m_yesText);
|
||||
m_yesX = COORD_YES_X - (yesWidth / 2);
|
||||
}
|
||||
|
||||
void center_no()
|
||||
{
|
||||
const int noWidth = sdl::text::get_width(22, m_noText);
|
||||
m_noX = COORD_NO_X - (noWidth / 2);
|
||||
}
|
||||
|
||||
void load_holding_strings()
|
||||
{
|
||||
for (int i = 0; const char *string = strings::get_by_name(strings::names::HOLDING_STRINGS, i); i++)
|
||||
{
|
||||
m_holdText[i] = string;
|
||||
}
|
||||
}
|
||||
|
||||
void confirmed()
|
||||
{
|
||||
auto newState = std::make_shared<StateType>(m_function, m_dataStruct);
|
||||
StateManager::push_state(newState);
|
||||
BaseState::deactivate();
|
||||
}
|
||||
|
||||
void hold_triggered()
|
||||
{
|
||||
m_startingTickCount = SDL_GetTicks64();
|
||||
ConfirmState::change_holding_text(0);
|
||||
}
|
||||
|
||||
void hold_sustained()
|
||||
{
|
||||
const uint64_t totalTicks = SDL_GetTicks64() - m_startingTickCount;
|
||||
const bool threeSeconds = totalTicks >= 3000;
|
||||
const bool twoSeconds = totalTicks >= 2000;
|
||||
const bool oneSecond = totalTicks >= 1000;
|
||||
|
||||
if (threeSeconds) { ConfirmState::confirmed(); }
|
||||
else if (twoSeconds) { ConfirmState::change_holding_text(2); }
|
||||
else if (oneSecond) { ConfirmState::change_holding_text(1); }
|
||||
}
|
||||
|
||||
void hold_released()
|
||||
{
|
||||
m_yesText = strings::get_by_name(strings::names::YES_NO_OK, 0);
|
||||
ConfirmState::center_yes();
|
||||
}
|
||||
|
||||
void cancelled()
|
||||
{
|
||||
FadeState::create_and_push(colors::DIM_BACKGROUND, 0x88, 0x00, nullptr);
|
||||
BaseState::deactivate();
|
||||
}
|
||||
|
||||
void change_holding_text(int index)
|
||||
{
|
||||
m_yesText = m_holdText[index];
|
||||
ConfirmState::center_yes();
|
||||
}
|
||||
};
|
||||
74
include/appstates/DataLoadingState.hpp
Normal file
74
include/appstates/DataLoadingState.hpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseTask.hpp"
|
||||
#include "data/DataContext.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "sys/OpTimer.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
class DataLoadingState final : public BaseTask
|
||||
{
|
||||
public:
|
||||
/// @brief This is a definition for functions that are called at destruction.
|
||||
using DestructFunction = std::function<void()>;
|
||||
|
||||
template <typename... Args>
|
||||
DataLoadingState(data::DataContext &context,
|
||||
DestructFunction destructFunction,
|
||||
void (*function)(sys::Task *, Args...),
|
||||
Args... args)
|
||||
: BaseTask()
|
||||
, m_context(context)
|
||||
, m_destructFunction(destructFunction)
|
||||
{
|
||||
DataLoadingState::initialize_static_members();
|
||||
m_task = std::make_unique<sys::Task>(function, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static inline std::shared_ptr<DataLoadingState> create(data::DataContext &context,
|
||||
DestructFunction destructFunction,
|
||||
void (*function)(sys::Task *, Args...),
|
||||
Args... args)
|
||||
{
|
||||
return std::make_shared<DataLoadingState>(context, destructFunction, function, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
static inline std::shared_ptr<DataLoadingState> create_and_push(data::DataContext &context,
|
||||
DestructFunction destructFunction,
|
||||
void (*function)(sys::Task *, Args...),
|
||||
Args... args)
|
||||
{
|
||||
auto newState = DataLoadingState::create(context, destructFunction, function, std::forward<Args>(args)...);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Update override.
|
||||
void update() override;
|
||||
|
||||
/// @brief Render override.
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Reference to the data context to run post-init operations.
|
||||
data::DataContext &m_context;
|
||||
|
||||
/// @brief X coord of the status text.
|
||||
int m_statusX{};
|
||||
|
||||
/// @brief The functions called upon destruction.
|
||||
DestructFunction m_destructFunction{};
|
||||
|
||||
/// @brief Icon displayed in the center of the screen.
|
||||
static inline sdl::SharedTexture sm_jksvIcon{};
|
||||
|
||||
/// @brief Loads the icon if it hasn't been already.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief
|
||||
void deactivate_state();
|
||||
};
|
||||
59
include/appstates/ExtrasMenuState.hpp
Normal file
59
include/appstates/ExtrasMenuState.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "ui/ControlGuide.hpp"
|
||||
#include "ui/Menu.hpp"
|
||||
|
||||
/// @brief Extras menu.
|
||||
class ExtrasMenuState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
ExtrasMenuState();
|
||||
|
||||
/// @brief Returns a new ExtrasMenuState
|
||||
static inline std::shared_ptr<ExtrasMenuState> create() { return std::make_shared<ExtrasMenuState>(); }
|
||||
|
||||
/// @brief Updates the menu.
|
||||
void update() override;
|
||||
|
||||
/// @brief Sub-update routine.
|
||||
void sub_update() override;
|
||||
|
||||
/// @brief Renders the menu to screen.
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Menu
|
||||
std::shared_ptr<ui::Menu> m_extrasMenu{};
|
||||
|
||||
/// @brief Render target for menu.
|
||||
sdl::SharedTexture m_renderTarget{};
|
||||
|
||||
/// @brief Control guider for bottom right corner.
|
||||
std::shared_ptr<ui::ControlGuide> m_controlGuide{};
|
||||
|
||||
/// @brief Creates and loads the menu strings.
|
||||
void initialize_menu();
|
||||
|
||||
/// @brief This function is called when Reinitialize data is selected.
|
||||
void reinitialize_data();
|
||||
|
||||
/// @brief Opens an SD to SD file browser.
|
||||
void sd_to_sd_browser();
|
||||
|
||||
/// @brief Opens the prodinfo-f to sd.
|
||||
void prodinfof_to_sd();
|
||||
|
||||
/// @brief Opens the safe partition to SD.
|
||||
void safe_to_sd();
|
||||
|
||||
/// @brief Opens the system partition to SD.
|
||||
void system_to_sd();
|
||||
|
||||
/// @brief Opens the user partition to SD.
|
||||
void user_to_sd();
|
||||
|
||||
/// @brief Terminates a process.
|
||||
void terminate_process();
|
||||
};
|
||||
81
include/appstates/FadeState.hpp
Normal file
81
include/appstates/FadeState.hpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class FadeState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Direction (In/Out) of the fade. This is auto-determined at construction.
|
||||
enum class Direction
|
||||
{
|
||||
In,
|
||||
Out
|
||||
};
|
||||
|
||||
/// @brief Creates a new fade in state.
|
||||
/// @param nextState The next state to push after the the fade is finished.
|
||||
FadeState(sdl::Color baseColor, uint8_t startAlpha, uint8_t endAlpha, std::shared_ptr<BaseState> nextState);
|
||||
|
||||
/// @brief Returns a new fade in state. See constructor.
|
||||
static inline std::shared_ptr<FadeState> create(sdl::Color baseColor,
|
||||
uint8_t startAlpha,
|
||||
uint8_t endAlpha,
|
||||
std::shared_ptr<BaseState> nextState)
|
||||
{
|
||||
return std::make_shared<FadeState>(baseColor, startAlpha, endAlpha, nextState);
|
||||
}
|
||||
|
||||
/// @brief Creates, returns and pushes a new FadeInState to the statemanager.
|
||||
static std::shared_ptr<FadeState> create_and_push(sdl::Color baseColor,
|
||||
uint8_t startAlpha,
|
||||
uint8_t endAlpha,
|
||||
std::shared_ptr<BaseState> nextState)
|
||||
{
|
||||
auto newState = FadeState::create(baseColor, startAlpha, endAlpha, nextState);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Update override.
|
||||
void update() override;
|
||||
|
||||
/// @brief Render override.
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
sdl::Color m_baseColor{};
|
||||
|
||||
/// @brief Alpha value.
|
||||
uint8_t m_alpha{};
|
||||
|
||||
/// @brief Alpha value to destruct at.
|
||||
uint8_t m_endAlpha{};
|
||||
|
||||
/// @brief Direction (in/out) of the fade. This is auto determined according to alpha values passed.
|
||||
FadeState::Direction m_direction{};
|
||||
|
||||
/// @brief The divisor found to make sure alpha ends evenly.
|
||||
uint8_t m_divisor{};
|
||||
|
||||
/// @brief Timer for fade.
|
||||
sys::Timer m_fadeTimer{};
|
||||
|
||||
/// @brief Pointer to the next state to push.
|
||||
std::shared_ptr<BaseState> m_nextState{};
|
||||
|
||||
/// @brief Finds the highest divisor for the fade to use.
|
||||
void find_divisor();
|
||||
|
||||
/// @brief Decreases alpha by m_divisor.
|
||||
void decrease_alpha();
|
||||
|
||||
/// @brief Increases alpha by m_divisor.
|
||||
void increase_alpha();
|
||||
|
||||
/// @brief Completes the fade.
|
||||
void completed();
|
||||
};
|
||||
150
include/appstates/FileModeState.hpp
Normal file
150
include/appstates/FileModeState.hpp
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
class FileModeState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new FileModeState.
|
||||
FileModeState(std::string_view mountA, std::string_view mountB, int64_t journalSize = 0, bool isSystem = false);
|
||||
|
||||
static inline std::shared_ptr<FileModeState> create(std::string_view mountA,
|
||||
std::string_view mountB,
|
||||
int64_t journalSize = 0,
|
||||
bool isSystem = false)
|
||||
{
|
||||
return std::make_shared<FileModeState>(mountA, mountB, journalSize, isSystem);
|
||||
}
|
||||
|
||||
static inline std::shared_ptr<FileModeState> create_and_push(std::string_view mountA,
|
||||
std::string_view mountB,
|
||||
int64_t journalSize = 0,
|
||||
bool isSystem = false)
|
||||
{
|
||||
auto newState = std::make_shared<FileModeState>(mountA, mountB, journalSize, isSystem);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Update override.
|
||||
void update() override;
|
||||
|
||||
/// @brief Render override.
|
||||
void render() override;
|
||||
|
||||
/// @brief This thing is a headache without this.
|
||||
friend class FileOptionState;
|
||||
|
||||
private:
|
||||
/// @brief These store the mount points to close the filesystems upon construction.
|
||||
std::string m_mountA{};
|
||||
std::string m_mountB{};
|
||||
|
||||
/// @brief These are the actual target paths.
|
||||
fslib::Path m_pathA{};
|
||||
fslib::Path m_pathB{};
|
||||
|
||||
/// @brief Directory listings for each respective path.
|
||||
fslib::Directory m_dirA{};
|
||||
fslib::Directory m_dirB{};
|
||||
|
||||
/// @brief Menus for the directory listings.
|
||||
std::shared_ptr<ui::Menu> m_dirMenuA{};
|
||||
std::shared_ptr<ui::Menu> m_dirMenuB{};
|
||||
|
||||
/// @brief Controls which menu/filesystem is currently targetted.
|
||||
bool m_target{};
|
||||
|
||||
/// @brief Stores the size for committing data (if needed) to mountA.
|
||||
int64_t m_journalSize{};
|
||||
|
||||
/// @brief Stores whether or not the panel should be closed.
|
||||
bool m_close{};
|
||||
|
||||
/// @brief Transition for the pop-up effect.
|
||||
ui::Transition m_transition{};
|
||||
|
||||
/// @brief Stores whether the instance is dealing with sensitive data.
|
||||
bool m_isSystem{};
|
||||
|
||||
/// @brief Stores the config setting from config to allow writing to the sensitive parts of the system.
|
||||
bool m_allowSystem{};
|
||||
|
||||
/// @brief Frame shared by all instances.
|
||||
static inline std::shared_ptr<ui::Frame> sm_frame{};
|
||||
|
||||
/// @brief This is the render target the browsers are rendered to.
|
||||
static inline sdl::SharedTexture sm_renderTarget{};
|
||||
|
||||
/// @brief Control guide shared by all instances.
|
||||
static inline std::shared_ptr<ui::ControlGuide> sm_controlGuide{};
|
||||
|
||||
/// @brief Initializes the members shared by all instances of FileModeState.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Creates valid paths with the mounts passed.
|
||||
void initialize_paths();
|
||||
|
||||
/// @brief Ensures the menus are allocated and setup properly.
|
||||
void initialize_menus();
|
||||
|
||||
/// @brief Loads the current directory listings and menus.
|
||||
void initialize_directory_menu(const fslib::Path &path, fslib::Directory &directory, ui::Menu &menu);
|
||||
|
||||
/// @brief Starts the dialog hiding process.
|
||||
void hide_dialog() noexcept;
|
||||
|
||||
/// @brief Returns whether or not the dialog is hidden.
|
||||
bool is_hidden() noexcept;
|
||||
|
||||
/// @brief Handles changing the current directory or opening the options.
|
||||
void enter_selected(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu);
|
||||
|
||||
/// @brief Opens the little option pop-up thingy.
|
||||
void open_option_menu(fslib::Directory &directory, ui::Menu &menu);
|
||||
|
||||
/// @brief Changes the current target/controllable menu.
|
||||
void change_target() noexcept;
|
||||
|
||||
/// @brief Function executed when '..' is selected.
|
||||
void up_one_directory(fslib::Path &path, fslib::Directory &directory, ui::Menu &menu);
|
||||
|
||||
/// @brief Appends the entry passed to the path passed and "enters" the directory.
|
||||
/// @param path Working path.
|
||||
/// @param directory Working directory.
|
||||
/// @param menu Working menu.
|
||||
/// @param entry Target entry.
|
||||
void enter_directory(fslib::Path &path,
|
||||
fslib::Directory &directory,
|
||||
ui::Menu &menu,
|
||||
const fslib::DirectoryEntry &entry);
|
||||
|
||||
/// @brief Returns a reference to the currently active menu.
|
||||
ui::Menu &get_source_menu() noexcept;
|
||||
|
||||
/// @brief Returns a reference to the currently inactive menu.
|
||||
ui::Menu &get_destination_menu() noexcept;
|
||||
|
||||
/// @brief Returns a reference to the current "active" path.
|
||||
fslib::Path &get_source_path() noexcept;
|
||||
|
||||
/// @brief Returns a reference to the currently "inactive" path.
|
||||
fslib::Path &get_destination_path() noexcept;
|
||||
|
||||
/// @brief Returns a reference to the "active" directory.
|
||||
fslib::Directory &get_source_directory() noexcept;
|
||||
|
||||
/// @brief Returns a reference ot the currently "inactive" directory.
|
||||
fslib::Directory &get_destination_directory() noexcept;
|
||||
|
||||
/// @brief Returns whether or not a path is at the root.
|
||||
inline bool path_is_root(fslib::Path &path) const { return std::char_traits<char>::length(path.get_path()) <= 1; }
|
||||
|
||||
/// @brief Closes the filesystems passed and deactivates the state.
|
||||
void deactivate_state() noexcept;
|
||||
};
|
||||
147
include/appstates/FileOptionState.hpp
Normal file
147
include/appstates/FileOptionState.hpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "appstates/FileModeState.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
class FileOptionState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief FileOptionState.
|
||||
/// @param spawningState Pointer to spawning state to grab its goodies.
|
||||
FileOptionState(FileModeState *spawningState);
|
||||
|
||||
/// @brief Inline creation function.
|
||||
static inline std::shared_ptr<FileOptionState> create(FileModeState *spawningState)
|
||||
{
|
||||
return std::make_shared<FileOptionState>(spawningState);
|
||||
}
|
||||
|
||||
/// @brief Same as above. Pushes state before returning it.
|
||||
static inline std::shared_ptr<FileOptionState> create_and_push(FileModeState *spawningState)
|
||||
{
|
||||
auto newState = FileOptionState::create(spawningState);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Update routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Render routine.
|
||||
void render() override;
|
||||
|
||||
/// @brief Signals to this state to update the source/target menu on the next update() call.
|
||||
void update_source();
|
||||
|
||||
/// @brief Signals to this state to update the destination. Very rarely used.
|
||||
void update_destination();
|
||||
|
||||
// clang-format off
|
||||
struct DataStruct
|
||||
{
|
||||
fslib::Path sourcePath{};
|
||||
fslib::Path destPath{};
|
||||
int64_t journalSize{};
|
||||
FileOptionState *spawningState{};
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
/// @brief This makes some other stuff easier to read and type.
|
||||
using TaskData = std::shared_ptr<FileOptionState::DataStruct>;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to spawning FileMode state.
|
||||
FileModeState *m_spawningState{};
|
||||
|
||||
/// @brief Stores the target for easier access.
|
||||
bool m_target{};
|
||||
|
||||
/// @brief Transition.
|
||||
ui::Transition m_transition{};
|
||||
|
||||
/// @brief Whether or not the state should be closed.
|
||||
bool m_close{};
|
||||
|
||||
/// @brief Stores whether or not an update is needed on the next update().
|
||||
std::atomic<bool> m_updateSource{};
|
||||
std::atomic<bool> m_updateDest{};
|
||||
|
||||
/// @brief This is the data struct passed to tasks.
|
||||
std::shared_ptr<FileOptionState::DataStruct> m_dataStruct{};
|
||||
|
||||
/// @brief This is shared by all instances.
|
||||
static inline std::shared_ptr<ui::Menu> sm_copyMenu{};
|
||||
|
||||
/// @brief This is shared by all instances.
|
||||
static inline std::shared_ptr<ui::DialogBox> sm_dialog{};
|
||||
|
||||
/// @brief Ensures static members of all instances are allocated.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Assigns the pointer to this.
|
||||
void initialize_data_struct();
|
||||
|
||||
/// @brief Updates the FileModeState's source data.
|
||||
void update_filemode_source();
|
||||
|
||||
/// @brief Updates the FileModeState's destination data.
|
||||
void update_filemode_dest();
|
||||
|
||||
/// @brief Sets up and begins the copy task.
|
||||
void copy_target();
|
||||
|
||||
/// @brief Sets up and begins the delete task.
|
||||
void delete_target();
|
||||
|
||||
/// @brief Attempts to rename the target.
|
||||
void rename_target();
|
||||
|
||||
/// @brief Attempts to create a new directory.
|
||||
void create_directory();
|
||||
|
||||
/// @brief Gets the properties of a file/folder.
|
||||
void get_show_target_properties();
|
||||
|
||||
/// @brief Gets info and creates a MessageState displaying the properties of the target directory.
|
||||
void get_show_directory_properties(const fslib::Path &path);
|
||||
|
||||
/// @brief Gets info and creates a message displaying the properties of the target file.
|
||||
/// @param path
|
||||
void get_show_file_properties(const fslib::Path &path);
|
||||
|
||||
/// @brief Pops the error writing to system message.
|
||||
void pop_system_error();
|
||||
|
||||
/// @brief Closes and hides the state.
|
||||
void close();
|
||||
|
||||
/// @brief Returns whether or not the state is closed.
|
||||
bool is_closed();
|
||||
|
||||
/// @brief Sets the menu index back to 0 and deactivates the state.
|
||||
void deactivate_state();
|
||||
|
||||
/// @brief Returns if the copy/from is allowed before continuing.
|
||||
inline bool system_write_check()
|
||||
{
|
||||
const bool target = m_spawningState->m_target;
|
||||
const bool isSystem = m_spawningState->m_isSystem;
|
||||
const bool allowSystem = m_spawningState->m_allowSystem;
|
||||
|
||||
return target && isSystem && !allowSystem;
|
||||
}
|
||||
|
||||
/// @brief Returns if the operation is allowed.
|
||||
inline bool system_operation_check()
|
||||
{
|
||||
const bool target = m_spawningState->m_target;
|
||||
const bool isSystem = m_spawningState->m_isSystem;
|
||||
const bool allowSystem = m_spawningState->m_allowSystem;
|
||||
|
||||
return !target && isSystem && !allowSystem;
|
||||
}
|
||||
};
|
||||
107
include/appstates/MainMenuState.hpp
Normal file
107
include/appstates/MainMenuState.hpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "ui/ControlGuide.hpp"
|
||||
#include "ui/IconMenu.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
/// @brief The main
|
||||
class MainMenuState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Creates and initializes the main menu.
|
||||
MainMenuState();
|
||||
|
||||
/// @brief Returns a new MainMenuState
|
||||
static inline std::shared_ptr<MainMenuState> create() { return std::make_shared<MainMenuState>(); }
|
||||
|
||||
/// @brief Creates and returns a new MainMenuState. Pushes it automatically.
|
||||
static inline std::shared_ptr<MainMenuState> create_and_push()
|
||||
{
|
||||
auto newState = MainMenuState::create();
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Runs update routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs the sub-update routine.
|
||||
void sub_update() override;
|
||||
|
||||
/// @brief Renders menu to screen.
|
||||
void render() override;
|
||||
|
||||
/// @brief Signals to
|
||||
static void initialize_view_states();
|
||||
|
||||
/// @brief Calls refresh on on view states in the vector.
|
||||
static void refresh_view_states();
|
||||
|
||||
// clang-format off
|
||||
struct DataStruct
|
||||
{
|
||||
data::UserList userList;
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
using TaskData = std::shared_ptr<MainMenuState::DataStruct>;
|
||||
|
||||
private:
|
||||
/// @brief Render target this state renders to.
|
||||
sdl::SharedTexture m_renderTarget{};
|
||||
|
||||
/// @brief The background gradient.
|
||||
sdl::SharedTexture m_background{};
|
||||
|
||||
/// @brief Icon for the settings option,
|
||||
sdl::SharedTexture m_settingsIcon{};
|
||||
|
||||
/// @brief Icon for the extras option.
|
||||
sdl::SharedTexture m_extrasIcon{};
|
||||
|
||||
/// @brief Special menu type that uses icons.
|
||||
std::shared_ptr<ui::IconMenu> m_mainMenu{};
|
||||
|
||||
/// @brief Control guide in the bottom right.
|
||||
std::shared_ptr<ui::ControlGuide> m_controlGuide{};
|
||||
|
||||
/// @brief This is the data struct passed to tasks.
|
||||
MainMenuState::TaskData m_dataStruct{};
|
||||
|
||||
/// @brief Records the size of the sm_users vector.
|
||||
static inline int sm_userCount{};
|
||||
|
||||
/// @brief This is the list of user pointers from data.
|
||||
static inline data::UserList sm_users{};
|
||||
|
||||
/// @brief This is the pointer to the settings state.
|
||||
static inline std::shared_ptr<BaseState> sm_settingsState{};
|
||||
|
||||
/// @brief This is the pointer to the extras state.
|
||||
static inline std::shared_ptr<BaseState> sm_extrasState{};
|
||||
|
||||
/// @brief This is the vector of title selection states.
|
||||
static inline std::vector<std::shared_ptr<BaseState>> sm_states{};
|
||||
|
||||
/// @brief Creates the settings and extras.
|
||||
void initialize_settings_extras();
|
||||
|
||||
/// @brief Pushes the icons to the main menu.
|
||||
void initialize_menu();
|
||||
|
||||
/// @brief Initializes the data struct.
|
||||
void initialize_data_struct();
|
||||
|
||||
/// @brief Pushes the target state to the vector.
|
||||
void push_target_state();
|
||||
|
||||
/// @brief Creates the user option state.
|
||||
void create_user_options();
|
||||
|
||||
/// @brief Backups up all save data for all users.
|
||||
void backup_all_for_all();
|
||||
};
|
||||
67
include/appstates/MessageState.hpp
Normal file
67
include/appstates/MessageState.hpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "appstates/FadeState.hpp"
|
||||
#include "graphics/colors.hpp"
|
||||
#include "ui/DialogBox.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class MessageState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
/// @param message Message to display.
|
||||
MessageState(std::string_view message);
|
||||
|
||||
/// @brief Creates and returns a new MessageState. See constructor.
|
||||
static inline std::shared_ptr<MessageState> create(std::string_view message)
|
||||
{
|
||||
return std::make_shared<MessageState>(message);
|
||||
}
|
||||
|
||||
/// @brief Same as above, only pushed to the StateManager before return.
|
||||
static inline std::shared_ptr<MessageState> create_and_push(std::string_view message)
|
||||
{
|
||||
auto newState = MessageState::create(message);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Same as above, but creates and pushes a transition fade in between.
|
||||
static inline std::shared_ptr<MessageState> create_and_push_fade(std::string_view message)
|
||||
{
|
||||
auto newState = MessageState::create(message);
|
||||
auto fadeState = FadeState::create_and_push(colors::DIM_BACKGROUND, 0x00, 0x88, newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Update override.
|
||||
void update() override;
|
||||
|
||||
/// @brief Render override
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Safe store of the message to display.
|
||||
std::string m_message{};
|
||||
|
||||
/// @brief Prevents the state from auto triggering from a previous frame.
|
||||
bool m_triggerGuard{};
|
||||
|
||||
/// @brief This is the OK string.
|
||||
static inline const char *sm_okText{};
|
||||
|
||||
/// @brief The center X coord for the OK [A]
|
||||
static inline int sm_okX{};
|
||||
|
||||
/// @brief All instances share this. There's no point in constantly allocating a new one.
|
||||
static inline std::shared_ptr<ui::DialogBox> sm_dialog{};
|
||||
|
||||
/// @brief Allocates and ensures ^
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Pushes and empty fade in and marks the stage for purging.
|
||||
void deactivate_state();
|
||||
};
|
||||
75
include/appstates/ProgressState.hpp
Normal file
75
include/appstates/ProgressState.hpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseTask.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
|
||||
/// @brief State that shows progress of a task.
|
||||
class ProgressState final : public BaseTask
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new ProgressState.
|
||||
/// @param function Function for the task to run.
|
||||
/// @param args Variadic arguments to be forwarded to the function passed.
|
||||
/// @note All functions passed to this must follow this signature: void function(sys::ProgressTask *, <arguments>)
|
||||
template <typename... Args>
|
||||
ProgressState(void (*function)(sys::ProgressTask *, Args...), Args... args)
|
||||
: BaseTask()
|
||||
{
|
||||
ProgressState::initialize_static_members();
|
||||
m_task = std::make_unique<sys::ProgressTask>(function, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// @brief Creates and returns a new progress state.
|
||||
template <typename... Args>
|
||||
static inline std::shared_ptr<ProgressState> create(void (*function)(sys::ProgressTask *, Args...), Args... args)
|
||||
{
|
||||
return std::make_shared<ProgressState>(function, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// @brief Creates, pushes, then returns a new ProgressState.
|
||||
template <typename... Args>
|
||||
static inline std::shared_ptr<ProgressState> create_and_push(void (*function)(sys::ProgressTask *, Args...),
|
||||
Args... args)
|
||||
{
|
||||
auto newState = ProgressState::create(function, std::forward<Args>(args)...);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Checks if the thread is finished and deactivates this state.
|
||||
void update() override;
|
||||
|
||||
/// @brief Renders the current progress to screen.
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Progress which is saved as a rounded whole number.
|
||||
size_t m_progress{};
|
||||
|
||||
/// @brief Width of the green bar in pixels.
|
||||
size_t m_progressBarWidth{};
|
||||
|
||||
/// @brief X coordinate of the percentage string.
|
||||
int m_percentageX{};
|
||||
|
||||
/// @brief Percentage as a string for printing to screen.
|
||||
std::string m_percentageString{};
|
||||
|
||||
/// @brief This is the dialog box everything is rendered to.
|
||||
static inline std::shared_ptr<ui::DialogBox> sm_dialog{};
|
||||
|
||||
/// @brief This is rendered over the edges of the bar to give it a slightly rounded look.
|
||||
static inline sdl::SharedTexture sm_barEdges{};
|
||||
|
||||
/// @brief Initializes the shared dialog box.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Performs some cleanup and marks the state for purging.
|
||||
void deactivate_state();
|
||||
};
|
||||
76
include/appstates/SaveCreateState.hpp
Normal file
76
include/appstates/SaveCreateState.hpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "appstates/TitleSelectCommon.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
/// @brief This is the state that is spawned when CreateSaveData is selected from the user menu.
|
||||
class SaveCreateState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new SaveCreateState.
|
||||
/// @param user The target user to create save data for.
|
||||
/// @param titleSelect The selection view for the user for refreshing and rendering.
|
||||
SaveCreateState(data::User *user, TitleSelectCommon *titleSelect);
|
||||
|
||||
/// @brief Returns a new SaveCreate state. See constructor for arguments.
|
||||
static inline std::shared_ptr<SaveCreateState> create(data::User *user, TitleSelectCommon *titleSelect)
|
||||
{
|
||||
return std::make_shared<SaveCreateState>(user, titleSelect);
|
||||
}
|
||||
|
||||
/// @brief Creates, pushes, returns and new SaveCreateState.
|
||||
static inline std::shared_ptr<SaveCreateState> create_and_push(data::User *user, TitleSelectCommon *titleSelect)
|
||||
{
|
||||
auto newState = SaveCreateState::create(user, titleSelect);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Runs the update routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render() override;
|
||||
|
||||
/// @brief This signals so data and the view can be refreshed on the next update() to avoid threading shenanigans.
|
||||
void refresh_required();
|
||||
|
||||
private:
|
||||
/// @brief Pointer to target user.
|
||||
data::User *m_user{};
|
||||
|
||||
/// @brief Pointer to title selection view for the current user.
|
||||
TitleSelectCommon *m_titleSelect{};
|
||||
|
||||
/// @brief Menu populated with every title found on the system.
|
||||
std::shared_ptr<ui::Menu> m_saveMenu{};
|
||||
|
||||
/// @brief Vector of pointers to the title info. This allows sorting them alphabetically and other things.
|
||||
std::vector<data::TitleInfo *> m_titleInfoVector{};
|
||||
|
||||
/// @brief Whether or not a refresh is required on the next update() call.
|
||||
std::atomic<bool> m_refreshRequired{};
|
||||
|
||||
/// @brief Shared slide panel all instances use. There's no point in allocating a new one every time.
|
||||
static inline std::unique_ptr<ui::SlideOutPanel> sm_slidePanel{};
|
||||
|
||||
/// @brief Initializes static members if they haven't been already.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Retrieves the data needed from data::
|
||||
void initialize_title_info_vector();
|
||||
|
||||
/// @brief Pushes the titles to the menu
|
||||
void initialize_menu();
|
||||
|
||||
/// @brief Launches the save creation task.
|
||||
void create_save_data_for();
|
||||
|
||||
/// @brief Performs some operations and marks the state for purging.
|
||||
void deactivate_state();
|
||||
};
|
||||
81
include/appstates/SettingsState.hpp
Normal file
81
include/appstates/SettingsState.hpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
#pragma once
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "ui/ControlGuide.hpp"
|
||||
#include "ui/Menu.hpp"
|
||||
|
||||
/// @brief The state for settings.
|
||||
class SettingsState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new settings state.
|
||||
SettingsState();
|
||||
|
||||
/// @brief Returns a new SettingsState.
|
||||
static inline std::shared_ptr<SettingsState> create() { return std::make_shared<SettingsState>(); }
|
||||
|
||||
/// @brief Runs the update routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Sub update routine.
|
||||
void sub_update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Menu for selecting and toggling settings.
|
||||
std::shared_ptr<ui::Menu> m_settingsMenu{};
|
||||
|
||||
// These are pointers to strings this state uses constantly.
|
||||
const char *m_onOff[2]{};
|
||||
const char *m_sortTypes[3]{};
|
||||
|
||||
/// @brief Control guide.
|
||||
std::shared_ptr<ui::ControlGuide> m_controlGuide{};
|
||||
|
||||
/// @brief Render target to render to.
|
||||
sdl::SharedTexture m_renderTarget{};
|
||||
|
||||
/// @brief Loads the settings menu strings.
|
||||
void load_settings_menu();
|
||||
|
||||
/// @brief Loads the on/off and sort type strings.
|
||||
void load_extra_strings();
|
||||
|
||||
/// @brief Runs a routine to update the menu strings for the menu.
|
||||
void update_menu_options();
|
||||
|
||||
/// @brief Changes the current output directory of JKSV.
|
||||
void change_working_directory();
|
||||
|
||||
/// @brief Creates and pushes the blacklist editing panel/state.
|
||||
void create_push_blacklist_edit();
|
||||
|
||||
/// @brief Toggles or executes the code to changed the selected menu option.
|
||||
void toggle_options();
|
||||
|
||||
/// @brief Creates and pushes the message with the description.
|
||||
void create_push_description_message();
|
||||
|
||||
/// @brief Cycles and wraps the Zip compression level.
|
||||
void cycle_zip_level();
|
||||
|
||||
/// @brief Cycles and wraps the title sort type.
|
||||
void cycle_sort_type();
|
||||
|
||||
/// @brief Toggles JKSM mode and calls the main menu to reinitialize the views.
|
||||
void toggle_jksm_mode();
|
||||
|
||||
/// @brief Toggles the trash folder and creates or deletes it if needed.
|
||||
void toggle_trash_folder();
|
||||
|
||||
/// @brief Cycles and wraps the animation scaling (1.0 to 4.0);
|
||||
void cycle_anim_scaling();
|
||||
|
||||
// Returns On/Off depending on the value passed.
|
||||
const char *get_status_text(uint8_t value);
|
||||
|
||||
/// @brief Returns the sort type depending on the value passed.
|
||||
const char *get_sort_type_text(uint8_t value);
|
||||
};
|
||||
49
include/appstates/TaskState.hpp
Normal file
49
include/appstates/TaskState.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseTask.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
/// @brief State that spawns a task and allows updates to be printed to screen.
|
||||
class TaskState final : public BaseTask
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs and spawns a new TaskState.
|
||||
/// @param function Function to run in the thread.
|
||||
/// @param args Variadic templated arguments to forward.
|
||||
/// @note All functions passed must follow this signature: void function(sys::Task *, <arguments>)
|
||||
template <typename... Args>
|
||||
TaskState(void (*function)(sys::Task *, Args...), Args... args)
|
||||
: BaseTask()
|
||||
{
|
||||
m_task = std::make_unique<sys::Task>(function, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// @brief Creates and returns a new TaskState.
|
||||
template <typename... Args>
|
||||
static inline std::shared_ptr<TaskState> create(void (*function)(sys::Task *, Args...), Args... args)
|
||||
{
|
||||
return std::make_shared<TaskState>(function, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// @brief Creates, pushes, then returns and new TaskState.
|
||||
template <typename... Args>
|
||||
static inline std::shared_ptr<TaskState> create_and_push(void (*function)(sys::Task *, Args...), Args... args)
|
||||
{
|
||||
auto newState = TaskState::create(function, std::forward<Args>(args)...);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Runs update routine. Waits for thread function to signal finish and deactivates.
|
||||
void update() override;
|
||||
|
||||
/// @brief Run render routine. Prints m_task's status string to screen, basically.
|
||||
/// @param
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Performs some operations and marks the state for deletion.
|
||||
void deactivate_state();
|
||||
};
|
||||
57
include/appstates/TextTitleSelectState.hpp
Normal file
57
include/appstates/TextTitleSelectState.hpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/TitleSelectCommon.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "ui/Menu.hpp"
|
||||
|
||||
/// @brief Text menu title selection state.
|
||||
class TextTitleSelectState final : public TitleSelectCommon
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs new text menu title selection state.
|
||||
/// @param user User to construct title select for.
|
||||
TextTitleSelectState(data::User *user);
|
||||
|
||||
/// @brief Creates and returns a new TextTitleSelect. See constructor.
|
||||
static inline std::shared_ptr<TextTitleSelectState> create(data::User *user)
|
||||
{
|
||||
return std::make_shared<TextTitleSelectState>(user);
|
||||
}
|
||||
|
||||
/// @brief Creates, pushes, and returns a new TextTitleSelect.
|
||||
static std::shared_ptr<TextTitleSelectState> create_and_push(data::User *user)
|
||||
{
|
||||
auto newState = TextTitleSelectState::create(user);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Runs update routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs render routine.
|
||||
void render() override;
|
||||
|
||||
/// @brief Refreshes view for changes.
|
||||
void refresh() override;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to user view "belongs" to.
|
||||
data::User *m_user{};
|
||||
|
||||
/// @brief Menu to display titles to select from.
|
||||
std::shared_ptr<ui::Menu> m_titleSelectMenu{};
|
||||
|
||||
/// @brief Target to render to.
|
||||
sdl::SharedTexture m_renderTarget{};
|
||||
|
||||
/// @brief Creates a new backup menu instance.
|
||||
void create_backup_menu();
|
||||
|
||||
/// @brief Creates a new instance of the title options menu.
|
||||
void create_title_option_menu();
|
||||
|
||||
/// @brief Adds or removes the current highlighted title to favorites.
|
||||
void add_remove_favorite();
|
||||
};
|
||||
67
include/appstates/TitleInfoState.hpp
Normal file
67
include/appstates/TitleInfoState.hpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class TitleInfoState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new title info state.
|
||||
/// @param user User to display info for.
|
||||
/// @param titleInfo Title to display info for.
|
||||
TitleInfoState(data::User *user, data::TitleInfo *titleInfo);
|
||||
|
||||
/// @brief Creates a new TitleInfoState.
|
||||
static inline std::shared_ptr<TitleInfoState> create(data::User *user, data::TitleInfo *titleInfo)
|
||||
{
|
||||
return std::make_shared<TitleInfoState>(user, titleInfo);
|
||||
}
|
||||
|
||||
/// @brief Creates, pushes, and returns a new TitleInfoState.
|
||||
static inline std::shared_ptr<TitleInfoState> create_and_push(data::User *user, data::TitleInfo *titleInfo)
|
||||
{
|
||||
auto newState = TitleInfoState::create(user, titleInfo);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Runs update routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs render routine.
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to user.
|
||||
data::User *m_user{};
|
||||
|
||||
/// @brief Pointer to title info.
|
||||
data::TitleInfo *m_titleInfo{};
|
||||
|
||||
/// @brief This is a pointer to the title's icon.
|
||||
sdl::SharedTexture m_icon{};
|
||||
|
||||
/// @brief This controls the clear color of the fields rendered.
|
||||
bool m_fieldClear{};
|
||||
|
||||
/// @brief Slide panel.
|
||||
static inline std::unique_ptr<ui::SlideOutPanel> sm_slidePanel{};
|
||||
|
||||
/// @brief Initializes the static members if they haven't been already.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Creates the scrolling text/cheating fields.
|
||||
void create_info_scrolls();
|
||||
|
||||
/// @brief Helper function for creating text fields.
|
||||
std::shared_ptr<ui::TextScroll> create_new_scroll(std::string_view text, int y);
|
||||
|
||||
/// @brief Performs some operations and marks the state for purging.
|
||||
void deactivate_state();
|
||||
};
|
||||
126
include/appstates/TitleOptionState.hpp
Normal file
126
include/appstates/TitleOptionState.hpp
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "appstates/TitleSelectCommon.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class TitleOptionState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new title option state.
|
||||
/// @param user Target user.
|
||||
/// @param titleInfo Target title.
|
||||
TitleOptionState(data::User *user, data::TitleInfo *titleInfo, TitleSelectCommon *titleSelect);
|
||||
|
||||
/// @brief Returns a new TitleOptionState. See constructor.
|
||||
static inline std::shared_ptr<TitleOptionState> create(data::User *user,
|
||||
data::TitleInfo *titleInfo,
|
||||
TitleSelectCommon *titleSelect)
|
||||
{
|
||||
return std::make_shared<TitleOptionState>(user, titleInfo, titleSelect);
|
||||
}
|
||||
|
||||
/// @brief Creates, pushes, and returns a new TitleOptionState
|
||||
static std::shared_ptr<TitleOptionState> create_and_push(data::User *user,
|
||||
data::TitleInfo *titleInfo,
|
||||
TitleSelectCommon *titleSelect)
|
||||
{
|
||||
auto newState = TitleOptionState::create(user, titleInfo, titleSelect);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Runs update routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Handles hiding the panel.
|
||||
void sub_update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render() override;
|
||||
|
||||
/// @brief This function allows tasks to signal to the spawning state to close itself on the next update() call.
|
||||
void close_on_update();
|
||||
|
||||
/// @brief Signals to the main thread that a view refresh is required on the next update() call.
|
||||
void refresh_required();
|
||||
|
||||
// clang-format off
|
||||
struct DataStruct
|
||||
{
|
||||
data::User *user{};
|
||||
data::TitleInfo *titleInfo{};
|
||||
TitleOptionState *spawningState{};
|
||||
TitleSelectCommon *titleSelect{};
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
using TaskData = std::shared_ptr<TitleOptionState::DataStruct>;
|
||||
|
||||
private:
|
||||
/// @brief This is just in case the option should only apply to the current user.
|
||||
data::User *m_user{};
|
||||
|
||||
/// @brief This is the target title.
|
||||
data::TitleInfo *m_titleInfo{};
|
||||
|
||||
/// @brief Pointer to the title selection being used for updating.
|
||||
TitleSelectCommon *m_titleSelect{};
|
||||
|
||||
/// @brief The struct passed to functions.
|
||||
std::shared_ptr<TitleOptionState::DataStruct> m_dataStruct{};
|
||||
|
||||
/// @brief This holds whether or not the state should deactivate itself on the next update loop.
|
||||
bool m_exitRequired{};
|
||||
|
||||
/// @brief This stores whether or a not a refresh is required on the next update().
|
||||
bool m_refreshRequired{};
|
||||
|
||||
/// @brief Menu used and shared by all instances.
|
||||
static inline std::shared_ptr<ui::Menu> sm_titleOptionMenu{};
|
||||
|
||||
/// @brief This is shared by all instances of this class.
|
||||
static inline std::unique_ptr<ui::SlideOutPanel> sm_slidePanel{};
|
||||
|
||||
/// @brief Initializes the static members all instances share.
|
||||
void initialize_static_members();
|
||||
|
||||
/// @brief Initializes the values of the struct passed to tasks.
|
||||
void initialize_data_struct();
|
||||
|
||||
/// @brief Creates and pushes the title information state.
|
||||
void create_push_info_state();
|
||||
|
||||
/// @brief Adds the currently highlighted title to the blacklist.
|
||||
void add_to_blacklist();
|
||||
|
||||
/// @brief Changes the current output directory for the title locally and remotely (if needed).
|
||||
void change_output_directory();
|
||||
|
||||
/// @brief Creates and pushes a new instance of file mode (once I get around to it.).
|
||||
void create_push_file_mode();
|
||||
|
||||
/// @brief Deletes all locally stored save backups for the current title.
|
||||
void delete_all_local_backups();
|
||||
|
||||
/// @brief Deletes all backups on the remote server.
|
||||
void delete_all_remote_backups();
|
||||
|
||||
/// @brief Resets the save data for the current title. Basically wipes it clean.
|
||||
void reset_save_data();
|
||||
|
||||
/// @brief Deletes the filesystem from the Switch.
|
||||
void delete_save_from_system();
|
||||
|
||||
/// @brief Extends the container to any size desired.
|
||||
void extend_save_container();
|
||||
|
||||
/// @brief Exports an SVI file for the current title.
|
||||
void export_svi_file();
|
||||
|
||||
/// @brief Performs some operations and marks the state for purging.
|
||||
void deactivate_state();
|
||||
};
|
||||
35
include/appstates/TitleSelectCommon.hpp
Normal file
35
include/appstates/TitleSelectCommon.hpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "ui/ControlGuide.hpp"
|
||||
|
||||
/// @brief Class that both view types are derived from.
|
||||
class TitleSelectCommon : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new TitleSelectCommon. Basically just calculates the X coordinate of the control if it wasn't
|
||||
/// already.
|
||||
TitleSelectCommon();
|
||||
|
||||
/// @brief Required destructor.
|
||||
virtual ~TitleSelectCommon() {};
|
||||
|
||||
/// @brief Required, inherited.
|
||||
virtual void update() = 0;
|
||||
|
||||
/// @brief Sub-update routine. Normally in a file, but I didn't feel like it really needed one.
|
||||
void sub_update() override;
|
||||
|
||||
/// @brief Required, inherited.
|
||||
virtual void render() = 0;
|
||||
|
||||
/// @brief Both derived classes need this function.
|
||||
virtual void refresh() = 0;
|
||||
|
||||
protected:
|
||||
/// @brief This is the control guide shared by all title selects.
|
||||
static inline std::shared_ptr<ui::ControlGuide> sm_controlGuide{};
|
||||
|
||||
private:
|
||||
/// @brief Initializes the control guide if it hasn't been already.
|
||||
void initialize_control_guide();
|
||||
};
|
||||
63
include/appstates/TitleSelectState.hpp
Normal file
63
include/appstates/TitleSelectState.hpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/TitleSelectCommon.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "ui/TitleView.hpp"
|
||||
|
||||
/// @brief Title select state with icon tiles.
|
||||
class TitleSelectState final : public TitleSelectCommon
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs new title select state.
|
||||
/// @param user User the state "belongs" to.
|
||||
TitleSelectState(data::User *user);
|
||||
|
||||
/// @brief Returns a new TitleSelect state.
|
||||
static inline std::shared_ptr<TitleSelectState> create(data::User *user)
|
||||
{
|
||||
return std::make_shared<TitleSelectState>(user);
|
||||
}
|
||||
|
||||
/// @brief Creates, pushes, and returns a new TitleSelectState.
|
||||
static inline std::shared_ptr<TitleSelectState> create_and_push(data::User *user)
|
||||
{
|
||||
auto newState = TitleSelectState::create(user);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Runs the update routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render() override;
|
||||
|
||||
/// @brief Refreshes the view.
|
||||
void refresh() override;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to the user the view belongs to.
|
||||
data::User *m_user{};
|
||||
|
||||
/// @brief Target to render to.
|
||||
sdl::SharedTexture m_renderTarget{};
|
||||
|
||||
/// @brief Tiled title selection view.
|
||||
std::shared_ptr<ui::TitleView> m_titleView{};
|
||||
|
||||
/// @brief Checks if the user still has any games left to list. This is a safety measure.
|
||||
bool title_count_check();
|
||||
|
||||
/// @brief Creates and pushes the backup menu state.
|
||||
void create_backup_menu();
|
||||
|
||||
/// @brief Creates and pushes the title option state.
|
||||
void create_title_option_menu();
|
||||
|
||||
/// @brief Resets and marks the state for purging.
|
||||
void deactivate_state();
|
||||
|
||||
/// @brief Adds or removes the currently highlighted game from the favorite vector.
|
||||
void add_remove_favorite();
|
||||
};
|
||||
98
include/appstates/UserOptionState.hpp
Normal file
98
include/appstates/UserOptionState.hpp
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#pragma once
|
||||
#include "StateManager.hpp"
|
||||
#include "appstates/BaseState.hpp"
|
||||
#include "appstates/TitleSelectCommon.hpp"
|
||||
#include "data/data.hpp"
|
||||
#include "ui/ui.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
/// @brief State that allows certain actions to be taken for users.
|
||||
class UserOptionState final : public BaseState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new UserOptionState.
|
||||
/// @param user Pointer to target user of the state.
|
||||
/// @param titleSelect Pointer to the selection state for refresh and rendering.
|
||||
UserOptionState(data::User *user, TitleSelectCommon *titleSelect);
|
||||
|
||||
/// @brief Returns a new UserOptionState. See constructor.
|
||||
static inline std::shared_ptr<UserOptionState> create(data::User *user, TitleSelectCommon *titleSelect)
|
||||
{
|
||||
return std::make_shared<UserOptionState>(user, titleSelect);
|
||||
}
|
||||
|
||||
/// @brief Creates, pushes, and returns a new UserOptionState.
|
||||
static inline std::shared_ptr<UserOptionState> create_and_push(data::User *user, TitleSelectCommon *titleSelect)
|
||||
{
|
||||
auto newState = UserOptionState::create(user, titleSelect);
|
||||
StateManager::push_state(newState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void update() override;
|
||||
|
||||
/// @brief Handles hiding the panel.
|
||||
void sub_update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render() override;
|
||||
|
||||
/// @brief Signals to the main update() function that a refresh is needed.
|
||||
/// @note Like this to prevent threading headaches.
|
||||
void refresh_required();
|
||||
|
||||
// clang-format off
|
||||
struct DataStruct
|
||||
{
|
||||
data::User *user{};
|
||||
UserOptionState *spawningState{};
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
using TaskData = std::shared_ptr<UserOptionState::DataStruct>;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to the target user.
|
||||
data::User *m_user{};
|
||||
|
||||
/// @brief Pointer to the selection view.
|
||||
TitleSelectCommon *m_titleSelect{};
|
||||
|
||||
/// @brief Menu that displays the options available.
|
||||
std::shared_ptr<ui::Menu> m_userOptionMenu{};
|
||||
|
||||
/// @brief Shared pointer to pass data to tasks and functions.
|
||||
std::shared_ptr<UserOptionState::DataStruct> m_dataStruct{};
|
||||
|
||||
/// @brief This allows spawned tasks to signal to the main thread to update the view.
|
||||
bool m_refreshRequired{};
|
||||
|
||||
/// @brief Slide panel all instances shared.
|
||||
static inline std::shared_ptr<ui::SlideOutPanel> sm_menuPanel{};
|
||||
|
||||
/// @brief Creates the panel if it hasn't been yet.
|
||||
void create_menu_panel();
|
||||
|
||||
/// @brief Creates and pushes the strings needed for the menu
|
||||
void load_menu_strings();
|
||||
|
||||
/// @brief Assigns the data within the struct to point where it needs to.
|
||||
void initialize_data_struct();
|
||||
|
||||
/// @brief Starts the backup all operation.
|
||||
void backup_all();
|
||||
|
||||
/// @brief Creates and pushes a new save creation menu.
|
||||
void create_save_create();
|
||||
|
||||
/// @brief Launches the create all save data for use task.
|
||||
void create_all_save_data();
|
||||
|
||||
/// @brief Deletes all save data for the user.
|
||||
void delete_all_save_data();
|
||||
|
||||
/// @brief Performs operations to reset static members and marks the state for purging.
|
||||
void deactivate_state();
|
||||
};
|
||||
121
include/config/ConfigContext.hpp
Normal file
121
include/config/ConfigContext.hpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <json-c/json.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace config
|
||||
{
|
||||
class ConfigContext
|
||||
{
|
||||
public:
|
||||
ConfigContext() = default;
|
||||
|
||||
/// @brief Ensures the config directory exists.
|
||||
void create_directory();
|
||||
|
||||
/// @brief Resets and saves the config back to the default values.
|
||||
void reset();
|
||||
|
||||
/// @brief Loads the config and custom paths files from the SD card if possible.
|
||||
bool load();
|
||||
|
||||
/// @brief Saves the config to the SD if possible.
|
||||
void save();
|
||||
|
||||
/// @brief Attempts to find and return the value of the key passed.
|
||||
uint8_t get_by_key(std::string_view key) const noexcept;
|
||||
|
||||
/// @brief Attempts to toggle the value for the key passed. For simple 1 and 0.
|
||||
void toggle_by_key(std::string_view key) noexcept;
|
||||
|
||||
/// @brief Attempts to set the key passed to the value passd.
|
||||
void set_by_key(std::string_view key, uint8_t value) noexcept;
|
||||
|
||||
/// @brief Returns the current working directory.
|
||||
fslib::Path get_working_directory() const;
|
||||
|
||||
/// @brief Sets the current work directory if the path passed is valid.
|
||||
bool set_working_directory(const fslib::Path &workDir) noexcept;
|
||||
|
||||
/// @brief Returns the transition scaling speed.
|
||||
double get_animation_scaling() const noexcept;
|
||||
|
||||
/// @brief Sets the current animation scaling speed.
|
||||
void set_animation_scaling(double scaling) noexcept;
|
||||
|
||||
/// @brief Adds a favorite to the favorite titles.
|
||||
void add_favorite(uint64_t applicationID);
|
||||
|
||||
/// @brief Removes a title from the favorites.
|
||||
void remove_favorite(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Returns if the application ID passed is a favorite.
|
||||
bool is_favorite(uint64_t applicationID) const noexcept;
|
||||
|
||||
/// @brief Adds the application ID passed to the blacklist.
|
||||
void add_to_blacklist(uint64_t applicationID);
|
||||
|
||||
/// @brief Removes the application ID passed from the blacklist.
|
||||
void remove_from_blacklist(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Writes all of the currently blacklisted titles to the vector passed.
|
||||
void get_blacklist(std::vector<uint64_t> &listOut);
|
||||
|
||||
/// @brief Returns if the application ID passed is found in the blacklist.
|
||||
bool is_blacklisted(uint64_t applicationID) const noexcept;
|
||||
|
||||
/// @brief Returns if the blacklist is empty.
|
||||
bool blacklist_empty() const noexcept;
|
||||
|
||||
/// @brief Returns if the application ID passed has a custom output path.
|
||||
bool has_custom_path(uint64_t applicationID) const noexcept;
|
||||
|
||||
/// @brief Adds a new output path.
|
||||
void add_custom_path(uint64_t applicationID, std::string_view newPath);
|
||||
|
||||
/// @brief Gets the custom output path of the applicationID passed.
|
||||
void get_custom_path(uint64_t applicationID, char *buffer, size_t bufferSize);
|
||||
|
||||
private:
|
||||
/// @brief This is where the majority of the config values are.
|
||||
std::map<std::string, uint8_t, std::less<>> m_configMap{};
|
||||
|
||||
/// @brief The main directory JKSV operates from.
|
||||
fslib::Path m_workingDirectory{};
|
||||
|
||||
/// @brief This scales the transitions.
|
||||
double m_animationScaling{};
|
||||
|
||||
/// @brief This holds the favorite titles.
|
||||
std::vector<uint64_t> m_favorites{};
|
||||
|
||||
/// @brief This holds the blacklisted titles.
|
||||
std::vector<uint64_t> m_blacklist{};
|
||||
|
||||
/// @brief This holds user defined paths.
|
||||
std::map<uint64_t, std::string> m_paths{};
|
||||
|
||||
/// @brief Loads the config file from SD.
|
||||
bool load_config_file();
|
||||
|
||||
/// @brief Saves the config to the SD.
|
||||
void save_config_file();
|
||||
|
||||
/// @brief Reads a json array to the vector passed.
|
||||
void read_array_to_vector(std::vector<uint64_t> &vector, json_object *array);
|
||||
|
||||
/// @brief Loads the custom output path file from the SD if possible.
|
||||
void load_custom_paths();
|
||||
|
||||
/// @brief Saves the custom output paths to the SD card.
|
||||
void save_custom_paths();
|
||||
|
||||
/// @brief Searches the vector passed for the application ID passed.
|
||||
std::vector<uint64_t>::const_iterator find_application_id(const std::vector<uint64_t> &vector,
|
||||
uint64_t applicationID) const;
|
||||
};
|
||||
}
|
||||
89
include/config/config.hpp
Normal file
89
include/config/config.hpp
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#pragma once
|
||||
#include "config/keys.hpp"
|
||||
#include "fslib.hpp"
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace config
|
||||
{
|
||||
/// @brief Attempts to load config from file. If it fails, loads defaults.
|
||||
void initialize();
|
||||
|
||||
/// @brief Resets config to default values.
|
||||
void reset_to_default();
|
||||
|
||||
/// @brief Saves config to file.
|
||||
void save();
|
||||
|
||||
/// @brief Retrieves the config value according to the key passed.
|
||||
/// @param key Key to retrieve. See config::keys
|
||||
/// @return Key's value if found. 0 if it is not.
|
||||
uint8_t get_by_key(std::string_view key) noexcept;
|
||||
|
||||
/// @brief Toggles the key. This is only for basic true or false settings.
|
||||
/// @param key Key to toggle.
|
||||
void toggle_by_key(std::string_view key) noexcept;
|
||||
|
||||
/// @brief Sets the key according
|
||||
/// @param key Key to set.
|
||||
/// @param value Value to set the key to.
|
||||
void set_by_key(std::string_view key, uint8_t value) noexcept;
|
||||
|
||||
/// @brief Returns the working directory.
|
||||
/// @return Working directory.
|
||||
fslib::Path get_working_directory();
|
||||
|
||||
/// @brief Attempts to set the working directory to the one passed.
|
||||
/// @param path Path for JKSV to use.
|
||||
bool set_working_directory(const fslib::Path &path) noexcept;
|
||||
|
||||
/// @brief Returns the scaling speed of UI transitions and animations.
|
||||
/// @return Scaling variable.
|
||||
double get_animation_scaling() noexcept;
|
||||
|
||||
/// @brief Sets the UI animation scaling.
|
||||
/// @param newScale New value to set the scaling to.
|
||||
void set_animation_scaling(double newScale) noexcept;
|
||||
|
||||
/// @brief Adds or removes a title from the favorites list.
|
||||
/// @param applicationID Application ID of title to add or remove.
|
||||
void add_remove_favorite(uint64_t applicationID);
|
||||
|
||||
/// @brief Returns if the title is found in the favorites list.
|
||||
/// @param applicationID Application ID to search for.
|
||||
/// @return True if found. False if not.
|
||||
bool is_favorite(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Adds or removes title from blacklist.
|
||||
/// @param applicationID Application ID to add or remove.
|
||||
void add_remove_blacklist(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Gets the currently blacklisted application IDs.
|
||||
/// @param listOut Vector to store application IDs to.
|
||||
void get_blacklisted_titles(std::vector<uint64_t> &listOut);
|
||||
|
||||
/// @brief Returns if the title is found in the blacklist.
|
||||
/// @param applicationID Application ID to search for.
|
||||
/// @return True if found. False if not.
|
||||
bool is_blacklisted(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Returns whether or not the blacklist is empty.
|
||||
bool blacklist_is_empty() noexcept;
|
||||
|
||||
/// @brief Adds a custom output path for the title.
|
||||
/// @param applicationID Application ID of title to add a path for.
|
||||
/// @param customPath Path to assign to the output.
|
||||
void add_custom_path(uint64_t applicationID, std::string_view customPath);
|
||||
|
||||
/// @brief Searches to see if the application ID passed has a custom output path.
|
||||
/// @param applicationID Application ID to check.
|
||||
/// @return True if it does. False if it doesn't.
|
||||
bool has_custom_path(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Gets the custom, defined path for the title.
|
||||
/// @param applicationID Application ID of title to get.
|
||||
/// @param pathOut Buffer to write the path to.
|
||||
/// @param pathOutSize Size of the buffer to write the path to.
|
||||
void get_custom_path(uint64_t applicationID, char *pathOut, size_t pathOutSize);
|
||||
} // namespace config
|
||||
31
include/config/keys.hpp
Normal file
31
include/config/keys.hpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include <string_view>
|
||||
|
||||
namespace config::keys
|
||||
{
|
||||
inline constexpr std::string_view WORKING_DIRECTORY = "WorkingDirectory";
|
||||
inline constexpr std::string_view INCLUDE_DEVICE_SAVES = "IncludeDeviceSaves";
|
||||
inline constexpr std::string_view AUTO_BACKUP_ON_RESTORE = "AutoBackupOnRestore";
|
||||
inline constexpr std::string_view AUTO_NAME_BACKUPS = "AutoNameBackups";
|
||||
inline constexpr std::string_view AUTO_UPLOAD = "AutoUploadToRemote";
|
||||
inline constexpr std::string_view USE_TITLE_IDS = "AlwaysUseTitleID";
|
||||
inline constexpr std::string_view HOLD_FOR_DELETION = "HoldForDeletion";
|
||||
inline constexpr std::string_view HOLD_FOR_RESTORATION = "HoldForRestoration";
|
||||
inline constexpr std::string_view HOLD_FOR_OVERWRITE = "HoldForOverWrite";
|
||||
inline constexpr std::string_view ONLY_LIST_MOUNTABLE = "OnlyListMountable";
|
||||
inline constexpr std::string_view LIST_ACCOUNT_SYS_SAVES = "ListAccountSystemSaves";
|
||||
inline constexpr std::string_view ALLOW_WRITING_TO_SYSTEM = "AllowSystemSaveWriting";
|
||||
inline constexpr std::string_view EXPORT_TO_ZIP = "ExportToZip";
|
||||
inline constexpr std::string_view ZIP_COMPRESSION_LEVEL = "ZipCompressionLevel";
|
||||
inline constexpr std::string_view TITLE_SORT_TYPE = "TitleSortType";
|
||||
inline constexpr std::string_view JKSM_TEXT_MODE = "JKSMTextMode";
|
||||
inline constexpr std::string_view FORCE_ENGLISH = "ForceEnglish";
|
||||
inline constexpr std::string_view SHOW_DEVICE_USER = "ShowDevice";
|
||||
inline constexpr std::string_view SHOW_BCAT_USER = "ShowBCAT";
|
||||
inline constexpr std::string_view SHOW_CACHE_USER = "ShowCache";
|
||||
inline constexpr std::string_view SHOW_SYSTEM_USER = "ShowSystem";
|
||||
inline constexpr std::string_view ENABLE_TRASH_BIN = "EnableTrash";
|
||||
inline constexpr std::string_view UI_ANIMATION_SCALE = "UIAnimationScaling";
|
||||
inline constexpr std::string_view FAVORITES = "Favorites";
|
||||
inline constexpr std::string_view BLACKLIST = "BlackList";
|
||||
}
|
||||
39
include/curl/DownloadStruct.hpp
Normal file
39
include/curl/DownloadStruct.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
namespace curl
|
||||
{
|
||||
// clang-format off
|
||||
struct DownloadStruct
|
||||
{
|
||||
/// @brief Buffer mutex.
|
||||
std::mutex lock{};
|
||||
|
||||
/// @brief Conditional for when the buffer is full.
|
||||
std::condition_variable condition{};
|
||||
|
||||
/// @brief Shared buffer that is read into.
|
||||
std::vector<sys::byte> sharedBuffer{};
|
||||
|
||||
/// @brief Bool to signal when the buffer is ready/empty.
|
||||
bool bufferReady{};
|
||||
|
||||
/// @brief Destination file to write to.
|
||||
fslib::File *dest{};
|
||||
|
||||
/// @brief Optional. Task to update with progress.
|
||||
sys::ProgressTask *task{};
|
||||
|
||||
/// @brief Current offset in the file.
|
||||
size_t offset{};
|
||||
|
||||
/// @brief Size of the file being downloaded.
|
||||
int64_t fileSize{};
|
||||
};
|
||||
// clang-format on
|
||||
}
|
||||
17
include/curl/UploadStruct.hpp
Normal file
17
include/curl/UploadStruct.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
|
||||
namespace curl
|
||||
{
|
||||
// clang-format off
|
||||
struct UploadStruct
|
||||
{
|
||||
/// @brief Source file to upload from.
|
||||
fslib::File *source{};
|
||||
|
||||
/// @brief Optional. Task to update with progress.
|
||||
sys::ProgressTask *task{};
|
||||
};
|
||||
// clang-format on
|
||||
}
|
||||
149
include/curl/curl.hpp
Normal file
149
include/curl/curl.hpp
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#pragma once
|
||||
#include "curl/DownloadStruct.hpp"
|
||||
#include "curl/UploadStruct.hpp"
|
||||
#include "fslib.hpp"
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/// @brief This namespace contains various wrapped libcurl functions and data.
|
||||
namespace curl
|
||||
{
|
||||
/// @brief JKSV's user agent string.
|
||||
static constexpr const char *STRING_USER_AGENT = "JKSV";
|
||||
|
||||
/// @brief Self cleaning curl handle.
|
||||
using Handle = std::unique_ptr<CURL, decltype(&curl_easy_cleanup)>;
|
||||
|
||||
/// @brief Self cleaning curl header/slist.
|
||||
using HeaderList = std::unique_ptr<curl_slist, decltype(&curl_slist_free_all)>;
|
||||
|
||||
/// @brief Definition for a vector containing headers received from libcurl.
|
||||
using HeaderArray = std::vector<std::string>;
|
||||
|
||||
/// @brief Initializes lib curl.
|
||||
/// @return True on success. False on failure.
|
||||
bool initialize();
|
||||
|
||||
/// @brief Exits libcurl
|
||||
void exit();
|
||||
|
||||
/// @brief Inline templated function to wrap curl_easy_setopt and make using curl::Handle slightly easier.
|
||||
/// @tparam Option Templated type of the option. This is a headache so let the compiler figure it out.
|
||||
/// @tparam Value Templated type of the value to set the option too. See above.
|
||||
/// @param handle curl::Handle the option is being set for.
|
||||
/// @param option CURLOPT to set.
|
||||
/// @param value Value to set the CURLOPT to.
|
||||
/// @return CURLcode returned from curl_easy_setopt.
|
||||
template <typename Option, typename Value>
|
||||
static inline CURLcode set_option(curl::Handle &handle, Option option, Value value)
|
||||
{
|
||||
return curl_easy_setopt(handle.get(), option, value);
|
||||
}
|
||||
|
||||
/// @brief Inline function that returns a self cleaning curl handle.
|
||||
/// @return Curl handle.
|
||||
static inline curl::Handle new_handle() { return curl::Handle(curl_easy_init(), curl_easy_cleanup); }
|
||||
|
||||
/// @brief Inline function that returns a nullptr'd self cleaning curl_list.
|
||||
/// @return Self cleaning curl_slist.
|
||||
static inline curl::HeaderList new_header_list() { return curl::HeaderList(nullptr, curl_slist_free_all); }
|
||||
|
||||
/// @brief Inline wrapper function for curl_easy_reset.
|
||||
/// @param curl curl::Handle to reset.
|
||||
static inline void reset_handle(curl::Handle &curl)
|
||||
{
|
||||
curl_easy_reset(curl.get());
|
||||
curl::set_option(curl, CURLOPT_USERAGENT, curl::STRING_USER_AGENT);
|
||||
curl::set_option(curl, CURLOPT_CONNECTTIMEOUT, 5L);
|
||||
}
|
||||
|
||||
/// @brief Logged inline wrapper function for curl_easy_perform.
|
||||
/// @param handle Handle to perform.
|
||||
bool perform(curl::Handle &handle);
|
||||
|
||||
/// @brief Inline wrapper function to make adding to HeaderList simpler.
|
||||
/// @param headerList Header list to append to.
|
||||
/// @param header Header to append.
|
||||
void append_header(curl::HeaderList &list, std::string_view header);
|
||||
|
||||
/// @brief Curl callback function for reading data from a file.
|
||||
/// @param buffer Incoming buffer from curl to read to.
|
||||
/// @param size Element size.
|
||||
/// @param count Element count.
|
||||
/// @param target Target file to read from.
|
||||
/// @return Number of bytes read so curl thinks everything went OK.
|
||||
size_t read_data_from_file(char *buffer, size_t size, size_t count, curl::UploadStruct *upload);
|
||||
|
||||
/// @brief Curl callback function that writes incoming headers to a vector/array.
|
||||
/// @param buffer Incoming buffer from curl.
|
||||
/// @param size Element size.
|
||||
/// @param count Element count.
|
||||
/// @param array Array to write the header to.
|
||||
/// @return size * count so curl thinks everything is fine, because it usually is.
|
||||
size_t write_header_array(const char *buffer, size_t size, size_t count, curl::HeaderArray *array);
|
||||
|
||||
/// @brief Curl callback function that writes the response data to a C++ string.
|
||||
/// @param buffer Incoming buffer from curl.
|
||||
/// @param size Element size.
|
||||
/// @param count Element count.
|
||||
/// @param string String to write the response to.
|
||||
/// @return size * count so curl thinks everything is fine.
|
||||
size_t write_response_string(const char *buffer, size_t size, size_t count, std::string *string);
|
||||
|
||||
/// @brief Curl callback function that writes data directly to an fslib::File pointer.
|
||||
/// @param buffer Incoming buffer from CURL.
|
||||
/// @param size Element size.
|
||||
/// @param count Element count.
|
||||
/// @param target File to write the data to.
|
||||
/// @return Number of bytes written to the file.
|
||||
size_t write_data_to_file(const char *buffer, size_t size, size_t count, fslib::File *target);
|
||||
|
||||
/// @brief Threaded version of the above.
|
||||
/// @param buffer Incoming data from curl
|
||||
/// @param size size
|
||||
/// @param count count
|
||||
/// @param download Struct containing data for threaded download.
|
||||
/// @return size * count
|
||||
size_t download_file_threaded(const char *buffer, size_t size, size_t count, curl::DownloadStruct *download);
|
||||
|
||||
/// @brief Function used to download files threaded.
|
||||
/// @param download Struct shared by both threads.
|
||||
void download_write_thread_function(curl::DownloadStruct &download);
|
||||
|
||||
/// @brief Gets the value of a header from an array of headers.
|
||||
/// @param array Array of headers to search.
|
||||
/// @param header Header to search for.
|
||||
/// @param valueOut String to write the value to.
|
||||
bool get_header_value(const curl::HeaderArray &array, std::string_view header, std::string &valueOut);
|
||||
|
||||
/// @brief Gets the response code from the handle passed.
|
||||
/// @param handle Handle to get the response code from.
|
||||
long get_response_code(curl::Handle &handle);
|
||||
|
||||
/// @brief Calls curl_easy_escape using the passed curl::Handle.
|
||||
/// @param handle Handle to use.
|
||||
/// @param in String to escape.
|
||||
/// @param out String to write the escaped text to.
|
||||
bool escape_string(curl::Handle &handle, std::string_view in, std::string &out);
|
||||
|
||||
/// @brief Calls curl_easy_unescape using the passed curl::Handle.
|
||||
/// @param handle Handle to use.
|
||||
/// @param in String to unescape.
|
||||
/// @param out String to write the escaped text to.
|
||||
bool unescape_string(curl::Handle &handle, std::string_view in, std::string &out);
|
||||
|
||||
/// @brief Prepares the curl handle passed for a get request.
|
||||
/// @param curl Handle to prepare for a get request.
|
||||
void prepare_get(curl::Handle &curl);
|
||||
|
||||
/// @brief Prepares the curl handle for a post request.
|
||||
/// @param curl Handle prepare for a post request.
|
||||
void prepare_post(curl::Handle &curl);
|
||||
|
||||
/// @brief Prepares the curl handle for an upload.
|
||||
/// @param curl Handle to reset and prepare for an upload.
|
||||
void prepare_upload(curl::Handle &curl);
|
||||
} // namespace curl
|
||||
25
include/data/DataCommon.hpp
Normal file
25
include/data/DataCommon.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "sdl.hpp"
|
||||
|
||||
namespace data
|
||||
{
|
||||
class DataCommon
|
||||
{
|
||||
public:
|
||||
/// @brief Default
|
||||
DataCommon() = default;
|
||||
|
||||
/// @brief Function to load the icon to a texture.
|
||||
virtual void load_icon() = 0;
|
||||
|
||||
/// @brief Returns the icon.
|
||||
sdl::SharedTexture get_icon() { return m_icon; };
|
||||
|
||||
/// @brief Sets the icon.
|
||||
void set_icon(sdl::SharedTexture &icon) { m_icon = icon; };
|
||||
|
||||
protected:
|
||||
/// @brief Shared texture of the icon.
|
||||
sdl::SharedTexture m_icon{};
|
||||
};
|
||||
}
|
||||
83
include/data/DataContext.hpp
Normal file
83
include/data/DataContext.hpp
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#pragma once
|
||||
#include "data/DataCommon.hpp"
|
||||
#include "data/TitleInfo.hpp"
|
||||
#include "data/User.hpp"
|
||||
#include "sys/Task.hpp"
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace data
|
||||
{
|
||||
class DataContext
|
||||
{
|
||||
public:
|
||||
/// @brief Default constructor.
|
||||
DataContext() = default;
|
||||
|
||||
/// @brief Loads the users from the system and creates the accounts for system users.
|
||||
bool load_create_users(sys::Task *task);
|
||||
|
||||
/// @brief Loops and runs the load routine for all users found.
|
||||
void load_user_save_info(sys::Task *task);
|
||||
|
||||
/// @brief Gets a vector of pointers to the users loaded.
|
||||
void get_users(data::UserList &listOut);
|
||||
|
||||
/// @brief Loads the titles from the Switch's application records.
|
||||
void load_application_records(sys::Task *task);
|
||||
|
||||
/// @brief Returns whether a title is loaded with the application ID passed.
|
||||
bool title_is_loaded(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Attempts to load a title with the application ID passed.
|
||||
void load_title(uint64_t applicationID);
|
||||
|
||||
/// @brief Returns the title info mapped to applicationID. nullptr on not found.
|
||||
data::TitleInfo *get_title_by_id(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Gets a vector of pointers to all of the current title info instances.
|
||||
void get_title_info_list(data::TitleInfoList &listOut);
|
||||
|
||||
/// @brief Gets a list of title info that has savedata for type.
|
||||
void get_title_info_list_by_type(FsSaveDataType type, data::TitleInfoList &listOut);
|
||||
|
||||
/// @brief Imports the SVI files from the SD card.
|
||||
void import_svi_files(sys::Task *task);
|
||||
|
||||
/// @brief Deletes the cache file if it exists.
|
||||
void delete_cache();
|
||||
|
||||
/// @brief Attempts to read the cache file from the SD card.
|
||||
bool read_cache(sys::Task *task);
|
||||
|
||||
/// @brief Writes the cache to file.
|
||||
bool write_cache(sys::Task *task);
|
||||
|
||||
/// @brief Processes the icon queue.
|
||||
void process_icon_queue();
|
||||
|
||||
private:
|
||||
/// @brief User vector.
|
||||
std::vector<data::User> m_users{};
|
||||
|
||||
/// @brief Map of titles paired with their application ID.
|
||||
std::unordered_map<uint64_t, data::TitleInfo> m_titleInfo{};
|
||||
|
||||
/// @brief Queue of the above to process the icons.
|
||||
std::vector<data::DataCommon *> m_iconQueue{};
|
||||
|
||||
/// @brief Mutex for users.
|
||||
std::mutex m_userMutex{};
|
||||
|
||||
/// @brief Mutex for titles.
|
||||
std::mutex m_titleMutex{};
|
||||
|
||||
/// @brief Mutex to make sure the icon queue doesn't get mutilated.
|
||||
std::mutex m_iconQueueMutex{};
|
||||
|
||||
/// @brief Whether or not the cache is still valid.
|
||||
bool m_cacheIsValid{};
|
||||
};
|
||||
}
|
||||
122
include/data/TitleInfo.hpp
Normal file
122
include/data/TitleInfo.hpp
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
#pragma once
|
||||
#include "data/DataCommon.hpp"
|
||||
#include "sdl.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
namespace data
|
||||
{
|
||||
class TitleInfo;
|
||||
|
||||
/// @brief Vector of pointers to titleinfo instances.
|
||||
using TitleInfoList = std::vector<data::TitleInfo *>;
|
||||
|
||||
/// @brief Class that holds data related to titles loaded from the system.
|
||||
class TitleInfo final : public data::DataCommon
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a TitleInfo instance. Loads control data, icon.
|
||||
/// @param applicationID Application ID of title to load.
|
||||
TitleInfo(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Initializes a TitleInfo instance using external (cached) NsApplicationControlData
|
||||
/// @param applicationID Application ID of the title loaded from cache.
|
||||
/// @param controlData Reference to the control data to init from.
|
||||
TitleInfo(uint64_t applicationID, NsApplicationControlData &controlData) noexcept;
|
||||
|
||||
// None of this nonesense around these parts.
|
||||
TitleInfo(const TitleInfo &) = delete;
|
||||
TitleInfo &operator=(const TitleInfo &) = delete;
|
||||
|
||||
/// @brief Returns the application ID of the title.
|
||||
/// @return Title's application ID.
|
||||
uint64_t get_application_id() const noexcept;
|
||||
|
||||
/// @brief Returns a pointer to the control data for the title.
|
||||
/// @return Pointer to control data.
|
||||
const NsApplicationControlData *get_control_data() const noexcept;
|
||||
|
||||
/// @brief Returns whether or not the title has control data.
|
||||
/// @return Whether or not the title has control data.
|
||||
bool has_control_data() const noexcept;
|
||||
|
||||
/// @brief Returns the title of the title?
|
||||
/// @return Title directly from the NACP.
|
||||
const char *get_title() const noexcept;
|
||||
|
||||
/// @brief Returns the path safe version of the title for file system usage.
|
||||
/// @return Path safe version of the title.
|
||||
const char *get_path_safe_title() const noexcept;
|
||||
|
||||
/// @brief Returns the publisher of the title.
|
||||
/// @return Publisher string from NACP.
|
||||
const char *get_publisher() const noexcept;
|
||||
|
||||
/// @brief Returns the owner ID of the save data.
|
||||
uint64_t get_save_data_owner_id() const noexcept;
|
||||
|
||||
/// @brief Returns the save data container's base size.
|
||||
/// @param saveType Type of save data to return.
|
||||
/// @return Size of baseline save data if applicable. If not, 0.
|
||||
int64_t get_save_data_size(uint8_t saveType) const noexcept;
|
||||
|
||||
/// @brief Returns the maximum size of the save data container.
|
||||
/// @param saveType Type of save data to return.
|
||||
/// @return Maximum size of the save container if applicable. If not, 0.
|
||||
int64_t get_save_data_size_max(uint8_t saveType) const noexcept;
|
||||
|
||||
/// @brief Returns the journaling size for the save type passed.
|
||||
/// @param saveType Save type to return.
|
||||
/// @return Journal size if applicable. If not, 0.
|
||||
int64_t get_journal_size(uint8_t saveType) const noexcept;
|
||||
|
||||
/// @brief Returns the maximum journal size for the save type passed.
|
||||
/// @param saveType Save type to return.
|
||||
/// @return Maximum journal size if applicable. If not, 0.
|
||||
int64_t get_journal_size_max(uint8_t saveType) const noexcept;
|
||||
|
||||
/// @brief Returns if a title uses the save type passed.
|
||||
/// @param saveType Save type to check for.
|
||||
/// @return True on success. False on failure.
|
||||
bool has_save_data_type(uint8_t saveType) const noexcept;
|
||||
|
||||
/// @brief Returns a pointer to the icon texture.
|
||||
/// @return Icon
|
||||
sdl::SharedTexture get_icon() const noexcept;
|
||||
|
||||
/// @brief Allows the path safe title to be set to a new path.
|
||||
/// @param newPathSafe Buffer containing the new safe path to use.
|
||||
void set_path_safe_title(const char *newPathSafe) noexcept;
|
||||
|
||||
/// @brief Loads the icon from the nacp.
|
||||
void load_icon() override;
|
||||
|
||||
private:
|
||||
/// @brief This defines how long the buffer is for the path safe version of the title.
|
||||
static inline constexpr size_t SIZE_PATH_SAFE = 0x200;
|
||||
|
||||
/// @brief Stores application ID for easier grabbing since JKSV is all pointers.
|
||||
uint64_t m_applicationID{};
|
||||
|
||||
/// @brief Where all the good stuff is.
|
||||
NsApplicationControlData m_data{};
|
||||
|
||||
/// @brief Stores the pointer to the language entry of the title.
|
||||
NacpLanguageEntry *m_entry{};
|
||||
|
||||
/// @brief Saves whether or not the title has control data.
|
||||
bool m_hasData{};
|
||||
|
||||
/// @brief This is the path safe version of the title.
|
||||
char m_pathSafeTitle[TitleInfo::SIZE_PATH_SAFE]{};
|
||||
|
||||
/// @brief Shared icon texture.
|
||||
sdl::SharedTexture m_icon{};
|
||||
|
||||
/// @brief Private function to get/create the path safe title.
|
||||
void get_create_path_safe_title() noexcept;
|
||||
};
|
||||
} // namespace data
|
||||
141
include/data/User.hpp
Normal file
141
include/data/User.hpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#pragma once
|
||||
#include "data/DataCommon.hpp"
|
||||
#include "fslib.hpp"
|
||||
#include "sdl.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <switch.h>
|
||||
#include <vector>
|
||||
|
||||
namespace data
|
||||
{
|
||||
class User;
|
||||
|
||||
/// @brief Type used to store save info and play statistics in the vector. Vector is used to preserve the order since I
|
||||
/// can't use a map without having to extra heap allocate it.
|
||||
using UserDataEntry = std::pair<uint64_t, std::pair<FsSaveDataInfo, PdmPlayStatistics>>;
|
||||
|
||||
/// @brief Type definition for the user save info/play stats vector.
|
||||
using UserSaveInfoList = std::vector<UserDataEntry>;
|
||||
|
||||
/// @brief A vector of pointers to User instances.
|
||||
using UserList = std::vector<data::User *>;
|
||||
|
||||
/// @brief Class that stores data for the user.
|
||||
class User final : public data::DataCommon
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new user with accountID
|
||||
/// @param accountID AccountID of user.
|
||||
/// @param saveType Save data type account uses.
|
||||
User(AccountUid accountID, FsSaveDataType saveType) noexcept;
|
||||
|
||||
/// @brief This is the constructor used to create the fake system users.
|
||||
/// @param accountID AccountID to associate with saveType.
|
||||
/// @param pathSafeNickname The path safe version of the save data since JKSV is in everything the Switch supports.
|
||||
/// @param iconPath Path to the icon to load for account.
|
||||
/// @param saveType Save data type of user.
|
||||
User(AccountUid accountID,
|
||||
std::string_view nickname,
|
||||
std::string_view pathSafeNickname,
|
||||
FsSaveDataType saveType) noexcept;
|
||||
|
||||
/// @brief Move constructor and operator.
|
||||
User(User &&user) noexcept;
|
||||
User &operator=(User &&user) noexcept;
|
||||
|
||||
// Non of this around these parts.
|
||||
User(const User &) = delete;
|
||||
User &operator=(const User &) = delete;
|
||||
|
||||
/// @brief Pushes data to m_userData
|
||||
/// @param saveInfo SaveDataInfo.
|
||||
/// @param playStats Play statistics.
|
||||
void add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistics *playStats);
|
||||
|
||||
/// @brief Clears the user save info vector.
|
||||
void clear_data_entries() noexcept;
|
||||
|
||||
/// @brief Erases data at index.
|
||||
/// @param index Index of save data info to erase.
|
||||
void erase_data(int index);
|
||||
|
||||
/// @brief Runs the sort algo on the vector.
|
||||
void sort_data() noexcept;
|
||||
|
||||
/// @brief Returns the account ID of the user
|
||||
AccountUid get_account_id() const noexcept;
|
||||
|
||||
/// @brief Returns the primary save data type o
|
||||
FsSaveDataType get_account_save_type() const noexcept;
|
||||
|
||||
/// @brief Returns the user's full UTF-8 nickname.
|
||||
const char *get_nickname() const noexcept;
|
||||
|
||||
/// @brief Returns the path safe version of the user's nickname.
|
||||
const char *get_path_safe_nickname() const noexcept;
|
||||
|
||||
/// @brief Returns the total data entries.
|
||||
size_t get_total_data_entries() const noexcept;
|
||||
|
||||
/// @brief Returns the application ID of the title at index.
|
||||
uint64_t get_application_id_at(int index) const noexcept;
|
||||
|
||||
/// @brief Returns a pointer to the save data info at index.
|
||||
FsSaveDataInfo *get_save_info_at(int index) noexcept;
|
||||
|
||||
/// @brief Returns a pointer to the play statistics at index.
|
||||
PdmPlayStatistics *get_play_stats_at(int index) noexcept;
|
||||
|
||||
/// @brief Returns a pointer to the save info of applicationID.
|
||||
FsSaveDataInfo *get_save_info_by_id(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Returns a reference to the internal map for range based loops.
|
||||
data::UserSaveInfoList &get_user_save_info_list() noexcept;
|
||||
|
||||
/// @brief Returns a pointer to the play statistics of applicationID
|
||||
PdmPlayStatistics *get_play_stats_by_id(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Erases a UserDataEntry according to the application ID passed.
|
||||
/// @param applicationID ID of the save to erase.
|
||||
void erase_save_info_by_id(uint64_t applicationID);
|
||||
|
||||
/// @brief Loads the save data info and play statistics for the current user using the information passed to the
|
||||
/// constructor.
|
||||
void load_user_data();
|
||||
|
||||
/// @brief Loads the icon from the system and converts it to a texture.
|
||||
void load_icon() override;
|
||||
|
||||
private:
|
||||
/// @brief Account's ID
|
||||
AccountUid m_accountID{};
|
||||
|
||||
/// @brief Type of save data account uses.
|
||||
FsSaveDataType m_saveType{};
|
||||
|
||||
/// @brief User's nickname.
|
||||
char m_nickname[0x20]{};
|
||||
|
||||
/// @brief Path safe version of nickname.
|
||||
char m_pathSafeNickname[0x20]{};
|
||||
|
||||
/// @brief Vector containing save info and play statistics.
|
||||
data::UserSaveInfoList m_userData{};
|
||||
|
||||
/// @brief Loads account structs from system.
|
||||
/// @param profile AccountProfile struct to write to.
|
||||
/// @param profileBase AccountProfileBase to write to.
|
||||
void load_account(AccountProfile &profile, AccountProfileBase &profileBase);
|
||||
|
||||
/// @brief Creates a placeholder since something went wrong.
|
||||
void create_account();
|
||||
|
||||
/// @brief Attempts to locate the data associated with applicationID
|
||||
data::UserSaveInfoList::iterator find_title_by_id(uint64_t applicationID);
|
||||
|
||||
/// @brief Returns whether or not the index is within bounds.
|
||||
inline bool index_check(int index) const { return index >= 0 && index < static_cast<int>(m_userData.size()); }
|
||||
};
|
||||
} // namespace data
|
||||
29
include/data/accountUID.hpp
Normal file
29
include/data/accountUID.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
// This solves a lot of problems.
|
||||
namespace data
|
||||
{
|
||||
static constexpr AccountUid BLANK_ACCOUNT_ID = {0};
|
||||
} // namespace data
|
||||
|
||||
/// @brief Allows comparison of AccountUids since devkitpro decided a struct with two uint64_t's is better than u128
|
||||
/// @param accountIDA First account to compare.
|
||||
/// @param accountIDB Second account to compare.
|
||||
/// @return True if both account IDs match.
|
||||
static inline bool operator==(AccountUid accountIDA, AccountUid accountIDB) noexcept
|
||||
{
|
||||
return (accountIDA.uid[0] == accountIDB.uid[0]) && (accountIDA.uid[1] == accountIDB.uid[1]);
|
||||
}
|
||||
|
||||
/// @brief Allows comparison of an AccountUid and a number.
|
||||
/// @param accountIDA AccountUid to compare.
|
||||
/// @param accountIDB Number to compare.
|
||||
/// @return True if they match. False if they don't.
|
||||
/// @note I'm not 100% sure which uint64_t in the AccountUid struct comes first. I don't know if it's [0][1] or [1][0]. To do:
|
||||
/// Figure that out.
|
||||
static inline bool operator==(AccountUid accountIDA, u128 accountIDB) noexcept
|
||||
{
|
||||
return accountIDA.uid[0] == (accountIDB >> 64 & 0xFFFFFFFFFFFFFFFF) &&
|
||||
accountIDA.uid[1] == (accountIDB & 0xFFFFFFFFFFFFFFFF);
|
||||
}
|
||||
43
include/data/data.hpp
Normal file
43
include/data/data.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include "data/TitleInfo.hpp"
|
||||
#include "data/User.hpp"
|
||||
#include "data/accountUID.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace data
|
||||
{
|
||||
/// @brief Launches the data loading/initialization state.
|
||||
/// @param clear Whether or not the cache should be cleared.
|
||||
/// @param onDestruction Function that is executed upon destruction of the data loading screen.
|
||||
void launch_initialization(bool clear, std::function<void()> onDestruction);
|
||||
|
||||
/// @brief Writes pointers to users to vectorOut
|
||||
/// @param userList List to push the pointers to.
|
||||
void get_users(data::UserList &userList);
|
||||
|
||||
/// @brief Returns a pointer to the title mapped to applicationID.
|
||||
/// @param applicationID ApplicationID of title to retrieve.
|
||||
/// @return Pointer to data. nullptr if it's not found.
|
||||
data::TitleInfo *get_title_info_by_id(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Gets a vector of pointers to the title info.
|
||||
/// @param listOut List to store pointers in.
|
||||
void get_title_info_list(data::TitleInfoList &listOut);
|
||||
|
||||
/// @brief Uses the application ID passed to add/load a title to the map.
|
||||
/// @param applicationID Application/System save data ID to add.
|
||||
void load_title_to_map(uint64_t applicationID);
|
||||
|
||||
/// @brief Returns if the title with applicationID is already loaded to the map.
|
||||
/// @param applicationID Application ID of the title to search for.
|
||||
/// @return True if it has been. False if it hasn't.
|
||||
bool title_exists_in_map(uint64_t applicationID) noexcept;
|
||||
|
||||
/// @brief Gets a vector of pointers with all titles with saveType.
|
||||
/// @param saveType Save data type to check for.
|
||||
/// @param vectorOut Vector to push pointers to.
|
||||
void get_title_info_by_type(FsSaveDataType saveType, data::TitleInfoList &listOut);
|
||||
} // namespace data
|
||||
15
include/error.hpp
Normal file
15
include/error.hpp
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <source_location>
|
||||
#include <switch.h>
|
||||
|
||||
namespace error
|
||||
{
|
||||
/// @brief Logs and returns if a call from libnx fails.
|
||||
bool libnx(Result code, const std::source_location &location = std::source_location::current()) noexcept;
|
||||
|
||||
/// @brief Logs and returns if an fslib function fails.
|
||||
bool fslib(bool result, const std::source_location &location = std::source_location::current()) noexcept;
|
||||
|
||||
/// @brief Returns whether or not the pointer passed is null. Records the location in which this occurred.
|
||||
bool is_null(const void *pointer, const std::source_location &location = std::source_location::current()) noexcept;
|
||||
}
|
||||
69
include/fs/MiniUnzip.hpp
Normal file
69
include/fs/MiniUnzip.hpp
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
|
||||
#include <minizip/unzip.h>
|
||||
#include <string_view>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
class MiniUnzip final
|
||||
{
|
||||
public:
|
||||
MiniUnzip() = default;
|
||||
|
||||
/// @brief Constructor that c
|
||||
MiniUnzip(const fslib::Path &path);
|
||||
|
||||
/// @brief Closes the unzFile.
|
||||
~MiniUnzip();
|
||||
|
||||
/// @brief Returns whether or not the unzFile was successfully opened.
|
||||
bool is_open() const noexcept;
|
||||
|
||||
/// @brief Attempts to open the path passed as a ZIP file.
|
||||
bool open(const fslib::Path &path);
|
||||
|
||||
/// @brief Closes the unzfile.
|
||||
void close();
|
||||
|
||||
/// @brief Attempts to go to the next file. Returns false at the end.
|
||||
bool next_file();
|
||||
|
||||
/// @brief Closes the currently open file.
|
||||
bool close_current_file();
|
||||
|
||||
/// @brief Attempts to locate a file with filename in the ZIP.
|
||||
bool locate_file(std::string_view filename);
|
||||
|
||||
/// @brief Resets to the beginning file.
|
||||
bool reset();
|
||||
|
||||
/// @brief Reads from the currently open file to the buffer passed.
|
||||
ssize_t read(void *buffer, size_t bufferSize);
|
||||
|
||||
/// @brief Returns if the entry is just a directory.
|
||||
bool is_directory() const noexcept;
|
||||
|
||||
/// @brief Returns the name of the current file.
|
||||
const char *get_filename() const noexcept;
|
||||
|
||||
/// @brief Returns the compressed size of the currently open file.
|
||||
uint64_t get_compressed_size() const noexcept;
|
||||
|
||||
/// @brief Returns the uncompressed size of the the currently open file.
|
||||
uint64_t get_uncompressed_size() const noexcept;
|
||||
|
||||
private:
|
||||
/// @brief Underlying unzFile.
|
||||
unzFile m_unz{};
|
||||
|
||||
/// @brief Saves whether or not opening the file was successful.
|
||||
bool m_isOpen{};
|
||||
|
||||
/// @brief Info for the current file.
|
||||
unz_file_info64 m_fileInfo{};
|
||||
|
||||
/// @brief Buffer containing the current file's name.
|
||||
char m_filename[FS_MAX_PATH]{};
|
||||
};
|
||||
}
|
||||
54
include/fs/MiniZip.hpp
Normal file
54
include/fs/MiniZip.hpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
|
||||
#include <minizip/zip.h>
|
||||
#include <string_view>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
class MiniZip final
|
||||
{
|
||||
public:
|
||||
MiniZip() = default;
|
||||
|
||||
/// @brief Constructor. Calls open upon construction;
|
||||
/// @param path
|
||||
MiniZip(const fslib::Path &path);
|
||||
|
||||
/// @brief Closes the zipFile.
|
||||
~MiniZip();
|
||||
|
||||
/// @brief Returns whether or not the zip file was successfully opened.
|
||||
/// @return
|
||||
bool is_open() const noexcept;
|
||||
|
||||
/// @brief Opens a Zip file at path
|
||||
bool open(const fslib::Path &path);
|
||||
|
||||
/// @brief Manual call for closing the zipFile.
|
||||
void close();
|
||||
|
||||
/// @brief Creates a new dummy directory entry in the ZIP.
|
||||
/// @param Path Path of the directory. Will be appended with a trailing slash if needed.
|
||||
void add_directory(std::string_view path);
|
||||
|
||||
/// @brief Opens a new file with filename as the path.
|
||||
bool open_new_file(std::string_view filename, bool trimPath = false, size_t trimPlaces = 0);
|
||||
|
||||
/// @brief Closes the currently open file in the Zip.
|
||||
bool close_current_file();
|
||||
|
||||
/// @brief Attempts to write the buffer passed to the currently opened file.
|
||||
bool write(const void *buffer, size_t dataSize);
|
||||
|
||||
private:
|
||||
/// @brief Stores whether or not the zipFile was opened successfully.
|
||||
bool m_isOpen{};
|
||||
|
||||
/// @brief Stores the compression level from config to avoid repeated calls.
|
||||
int m_level{};
|
||||
|
||||
/// @brief Underlying ZIP file.
|
||||
zipFile m_zip{};
|
||||
};
|
||||
}
|
||||
25
include/fs/PathFilter.hpp
Normal file
25
include/fs/PathFilter.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
class PathFilter
|
||||
{
|
||||
public:
|
||||
/// @brief Loads a path filter JSON file.
|
||||
PathFilter(const fslib::Path &filterPath);
|
||||
|
||||
/// @brief Returns whether or not the filter has valid paths.
|
||||
bool has_paths() const noexcept;
|
||||
|
||||
/// @brief Returns whether or not the path passed is filtered.
|
||||
bool is_filtered(const fslib::Path &path) const noexcept;
|
||||
|
||||
private:
|
||||
/// @brief Vector of paths to filter from deletion and backup.
|
||||
std::vector<fslib::Path> m_paths{};
|
||||
};
|
||||
}
|
||||
42
include/fs/SaveMetaData.hpp
Normal file
42
include/fs/SaveMetaData.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
#include "data/TitleInfo.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <switch.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
/// @brief This is the magic value written to the beginning.
|
||||
constexpr uint32_t SAVE_META_MAGIC = 0x56534B4A;
|
||||
|
||||
/// @brief This is the filename used for the save data meta info.
|
||||
static constexpr std::string_view NAME_SAVE_META = ".nx_save_meta.bin";
|
||||
|
||||
// clang-format off
|
||||
struct SaveMetaData
|
||||
{
|
||||
uint32_t magic{};
|
||||
uint8_t revision{};
|
||||
uint64_t applicationID{};
|
||||
AccountUid accountID{};
|
||||
uint64_t systemSaveID{};
|
||||
uint8_t saveDataType{};
|
||||
uint8_t saveDataRank{};
|
||||
uint16_t saveDataIndex{};
|
||||
uint64_t ownerID{};
|
||||
uint64_t timestamp{};
|
||||
uint32_t flags{};
|
||||
int64_t saveDataSize{};
|
||||
int64_t journalSize{};
|
||||
uint64_t commitID{};
|
||||
} __attribute__((packed));
|
||||
// clang-format on
|
||||
|
||||
/// @brief Didn't feel like a whole new file just for this. Fills an fs::SaveMetaData struct.
|
||||
bool fill_save_meta_data(const FsSaveDataInfo *saveInfo, SaveMetaData &meta) noexcept;
|
||||
|
||||
/// @brief Processes the save meta data and applies it to the passed saveInfo pointer.
|
||||
/// @param saveInfo FsSaveDataInfo to apply the meta to.
|
||||
/// @param meta Save meta data to apply.
|
||||
bool process_save_meta_data(const FsSaveDataInfo *saveInfo, const SaveMetaData &meta) noexcept;
|
||||
} // namespace fs
|
||||
37
include/fs/ScopedSaveMount.hpp
Normal file
37
include/fs/ScopedSaveMount.hpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <switch.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
class ScopedSaveMount
|
||||
{
|
||||
public:
|
||||
/// @brief Opens a scope save mount using the FsSaveDataInfo passed.
|
||||
/// @param mount Mount point.
|
||||
/// @param info Save info to mount.
|
||||
/// @param log Optional. Whether or not logging errors is wanted. True by default.
|
||||
ScopedSaveMount(std::string_view mount, const FsSaveDataInfo *saveInfo, bool log = true);
|
||||
|
||||
ScopedSaveMount(ScopedSaveMount &&scopedSaveMount) noexcept;
|
||||
ScopedSaveMount &operator=(ScopedSaveMount &&scopedSaveMount) noexcept;
|
||||
|
||||
ScopedSaveMount(const ScopedSaveMount &) = delete;
|
||||
ScopedSaveMount &operator=(const ScopedSaveMount &) = delete;
|
||||
|
||||
/// @brief Closes the save mounted.
|
||||
~ScopedSaveMount();
|
||||
|
||||
/// @brief Returns whether or not mounting the data was successful.
|
||||
bool is_open() const noexcept;
|
||||
|
||||
private:
|
||||
/// @brief Saves a copy of the mount point for destruction.
|
||||
std::string m_mountPoint{};
|
||||
|
||||
/// @brief Stores whether or not mounting the save was successful.
|
||||
bool m_isOpen{};
|
||||
|
||||
bool m_log{};
|
||||
};
|
||||
}
|
||||
21
include/fs/directory_functions.hpp
Normal file
21
include/fs/directory_functions.hpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
|
||||
namespace fs
|
||||
{
|
||||
/// @brief Recursively runs through the path passed and retrieves information.
|
||||
/// @param directoryPath Path of directory.
|
||||
/// @param subDirCount Int64_t to track number of subdirectories with.
|
||||
/// @param fileCount Int64_t to track the number of files.
|
||||
/// @param totalSize Int64_t to track the size of everything.
|
||||
/// @return True on success. False or crash on what I would assume is a stack overflow.
|
||||
bool get_directory_information(const fslib::Path &directoryPath,
|
||||
int64_t &subDirCount,
|
||||
int64_t &fileCount,
|
||||
int64_t &totalSize);
|
||||
|
||||
/// @brief Checks if directory is empty. Didn't feel like this needs its own source file.
|
||||
/// @param directoryPath Path to directory to check.
|
||||
/// @return True if directory has files inside.
|
||||
bool directory_has_contents(const fslib::Path &directoryPath);
|
||||
} // namespace fs
|
||||
10
include/fs/fs.hpp
Normal file
10
include/fs/fs.hpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
#include "fs/MiniUnzip.hpp"
|
||||
#include "fs/MiniZip.hpp"
|
||||
#include "fs/SaveMetaData.hpp"
|
||||
#include "fs/ScopedSaveMount.hpp"
|
||||
#include "fs/directory_functions.hpp"
|
||||
#include "fs/io.hpp"
|
||||
#include "fs/save_data_functions.hpp"
|
||||
#include "fs/save_mount.hpp"
|
||||
#include "fs/zip.hpp"
|
||||
41
include/fs/io.hpp
Normal file
41
include/fs/io.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
#include "sys/sys.hpp"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
/// @brief Copies source to destination.
|
||||
/// @param source Path to source file.
|
||||
/// @param destination Path to destination.
|
||||
/// @param journalSize Optional. The size of the journal if data needs to be commited.
|
||||
/// @param commitDevice Optional. The device to commit to if it's needed.
|
||||
/// @param Task Optional. Progress tracking task to display progress of operation if needed.
|
||||
void copy_file(const fslib::Path &source, const fslib::Path &destination, sys::ProgressTask *Task = nullptr);
|
||||
|
||||
/// @brief Same as a above. Committing data to the device passed while copying.
|
||||
/// @param device Device to commit data to.
|
||||
/// @param journalSize Size of the journal area of the save data.
|
||||
void copy_file_commit(const fslib::Path &source,
|
||||
const fslib::Path &destination,
|
||||
int64_t journalSize,
|
||||
sys::ProgressTask *task = nullptr);
|
||||
|
||||
/// @brief Recursively copies source to destination.
|
||||
/// @param source Source path.
|
||||
/// @param destination Destination path.
|
||||
/// @param journalSize Optional. Journal size to be passed to copyFile if data needs to be commited to device.
|
||||
/// @param commitDevice Optional. Device to commit data to if needed.
|
||||
/// @param Task Option. Progress tracking task to be passed to copyFile to show progress of operation.
|
||||
void copy_directory(const fslib::Path &source, const fslib::Path &destination, sys::ProgressTask *Task = nullptr);
|
||||
|
||||
/// @brief Same as above but committing data passed while copying.
|
||||
/// @param device Device to commit data to.
|
||||
/// @param journalSize Size of the journaling area of the save.
|
||||
void copy_directory_commit(const fslib::Path &source,
|
||||
const fslib::Path &destination,
|
||||
int64_t journalSize,
|
||||
sys::ProgressTask *task = nullptr);
|
||||
|
||||
} // namespace fs
|
||||
37
include/fs/save_data_functions.hpp
Normal file
37
include/fs/save_data_functions.hpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
#include "data/data.hpp"
|
||||
|
||||
#include <switch.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
/// @brief Creates save data for the target user for the title passed.
|
||||
/// @param targetUser User to create save data for.
|
||||
/// @param titleInfo Title to create save data for.
|
||||
/// @return True on success. False on failure.
|
||||
bool create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo) noexcept;
|
||||
|
||||
/// @brief Deletes the save data of the FsSaveDataInfo passed.
|
||||
/// @param saveInfo Save data to delete.
|
||||
/// @return True on success. False on failure.
|
||||
bool delete_save_data(const FsSaveDataInfo *saveInfo) noexcept;
|
||||
|
||||
/// @brief Extends the save data of the FsSaveDataInfo struct passed.
|
||||
/// @param saveInfo Pointer to the FsSaveDataInfo struct of the save to extend.
|
||||
/// @param size Size (in MB) to extend the save data to.
|
||||
/// @param journalSize Size of the journaling space.
|
||||
/// @return True on success. False on failure.
|
||||
bool extend_save_data(const FsSaveDataInfo *saveInfo, int64_t size, int64_t journalSize) noexcept;
|
||||
|
||||
/// @brief Returns whether or not the saveInfo passed is system type.
|
||||
/// @param saveInfo FsSaveDataInfo to check.
|
||||
/// @return True if it is. False if it isn't.
|
||||
/// @note The config setting overrides this.
|
||||
bool is_system_save_data(const FsSaveDataInfo *saveInfo) noexcept;
|
||||
|
||||
/// @brief Reads the extra info of the save container according to the FsSaveDataInfo passed.
|
||||
/// @param saveInfo Pointer to the save info to read.
|
||||
/// @param extraOut Reference to the FsSaveDataExtraData to read to.
|
||||
/// @return True on success. False on failure.
|
||||
bool read_save_extra_data(const FsSaveDataInfo *saveInfo, FsSaveDataExtraData &extraOut) noexcept;
|
||||
} // namespace fs
|
||||
12
include/fs/save_mount.hpp
Normal file
12
include/fs/save_mount.hpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <string_view>
|
||||
#include <switch.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
/// @brief Default mount point used for JKSV for saves.
|
||||
inline constexpr std::string_view DEFAULT_SAVE_MOUNT = "save";
|
||||
|
||||
/// @brief Same as above, but as a root directory.
|
||||
inline constexpr std::string_view DEFAULT_SAVE_ROOT = "save:/";
|
||||
} // namespace fs
|
||||
25
include/fs/zip.hpp
Normal file
25
include/fs/zip.hpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
// Major to do: Stop using minizip and finish the ZipFile class.
|
||||
#include "fs/MiniUnzip.hpp"
|
||||
#include "fs/MiniZip.hpp"
|
||||
#include "fs/fs.hpp"
|
||||
#include "fslib.hpp"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
/// @brief Copies source to destination.
|
||||
/// @note Task is optional.
|
||||
void copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys::ProgressTask *Task = nullptr);
|
||||
|
||||
/// @brief Unzips source to destination.
|
||||
/// @note Task is optional.
|
||||
void copy_zip_to_directory(fs::MiniUnzip &source,
|
||||
const fslib::Path &dest,
|
||||
int64_t journalSize,
|
||||
sys::ProgressTask *Task = nullptr);
|
||||
|
||||
/// @brief Returns whether or not zip has files inside besides the save meta.
|
||||
bool zip_has_contents(const fslib::Path &zipPath);
|
||||
} // namespace fs
|
||||
27
include/graphics/colors.hpp
Normal file
27
include/graphics/colors.hpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
#include "sdl.hpp"
|
||||
|
||||
namespace colors
|
||||
{
|
||||
inline constexpr sdl::Color WHITE = {0xFFFFFFFF};
|
||||
inline constexpr sdl::Color BLACK = {0x000000FF};
|
||||
inline constexpr sdl::Color RED = {0xFF0000FF};
|
||||
inline constexpr sdl::Color DARK_RED = {0xDD0000FF};
|
||||
inline constexpr sdl::Color GREEN = {0x00FF00FF};
|
||||
inline constexpr sdl::Color BLUE = {0x0099EEFF};
|
||||
inline constexpr sdl::Color YELLOW = {0xF8FC00FF};
|
||||
inline constexpr sdl::Color PINK = {0xFF4444FF};
|
||||
inline constexpr sdl::Color BLUE_GREEN = {0x00FFC5FF};
|
||||
inline constexpr sdl::Color CLEAR_COLOR = {0x2D2D2DFF};
|
||||
inline constexpr sdl::Color CLEAR_PANEL = {0x0D0D0DFF};
|
||||
inline constexpr sdl::Color DIALOG_DARK = {0x505050FF};
|
||||
inline constexpr sdl::Color DIALOG_LIGHT = {0xDCDCDCFF};
|
||||
inline constexpr sdl::Color DIM_BACKGROUND = {0x00000088};
|
||||
inline constexpr sdl::Color TRANSPARENT = {0x00000000};
|
||||
inline constexpr sdl::Color SLIDE_PANEL_CLEAR = {0x000000CC};
|
||||
inline constexpr sdl::Color DIV_COLOR = {0x707070FF};
|
||||
inline constexpr sdl::Color GUIDE_COLOR = {0x0000007F};
|
||||
|
||||
inline constexpr uint8_t ALPHA_FADE_BEGIN = 0x00;
|
||||
inline constexpr uint8_t ALPHA_FADE_END = 0x88;
|
||||
} // namespace colors
|
||||
16
include/graphics/gfxutil.hpp
Normal file
16
include/graphics/gfxutil.hpp
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
#include "sdl.hpp"
|
||||
|
||||
#include <string_view>
|
||||
// This file contains basic graphics functions various parts of JKSV use.
|
||||
|
||||
namespace gfxutil
|
||||
{
|
||||
/// @brief Generates a generic icon for saves and titles that lack one.
|
||||
/// @param text Text to be centered and rendered to the icon.
|
||||
/// @param fontSize Size of the font to use.
|
||||
/// @param background Background color to use.
|
||||
/// @param foreground Color to use to render the text.
|
||||
/// @return sdl::SharedTexture of the icon.
|
||||
sdl::SharedTexture create_generic_icon(std::string_view text, int fontSize, sdl::Color background, sdl::Color foreground);
|
||||
} // namespace gfxutil
|
||||
23
include/input.hpp
Normal file
23
include/input.hpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
namespace input
|
||||
{
|
||||
/// @brief Initializes PadState and input.
|
||||
void initialize();
|
||||
|
||||
/// @brief Updates the PadState.
|
||||
void update() noexcept;
|
||||
|
||||
/// @brief Returns if a button was pressed the current frame, but not the previous.
|
||||
/// @param button Button to check.
|
||||
bool button_pressed(HidNpadButton button) noexcept;
|
||||
|
||||
/// @brief Returns if the button was pressed or held the previous and current frame.
|
||||
/// @param button Button to check.
|
||||
bool button_held(HidNpadButton button) noexcept;
|
||||
|
||||
/// @brief Returns if the button was pressed or held the previous frame, but not the current.
|
||||
/// @param button Button to check.
|
||||
bool button_released(HidNpadButton button) noexcept;
|
||||
} // namespace input
|
||||
19
include/keyboard.hpp
Normal file
19
include/keyboard.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include <string_view>
|
||||
#include <switch.h>
|
||||
|
||||
namespace keyboard
|
||||
{
|
||||
/// @brief Gets input using the Switch's keyboard.
|
||||
/// @param keyboardType Type of keyboard shown.
|
||||
/// @param defaultText The default text in the keyboard.
|
||||
/// @param header The header of the keyboard.
|
||||
/// @param stringOut Pointer to buffer to write to.
|
||||
/// @param stringLength Size of the buffer to write too.
|
||||
/// @return True if input was successful and valid. False if it wasn't.
|
||||
bool get_input(SwkbdType keyboardType,
|
||||
std::string_view defaultText,
|
||||
std::string_view header,
|
||||
char *stringOut,
|
||||
size_t stringLength);
|
||||
} // namespace keyboard
|
||||
13
include/logging/logger.hpp
Normal file
13
include/logging/logger.hpp
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
#include <string_view>
|
||||
|
||||
namespace logger
|
||||
{
|
||||
/// @brief Creates the log file if it doesn't exist already.
|
||||
void initialize();
|
||||
|
||||
/// @brief Logs a formatted string.
|
||||
/// @param format Format of string.
|
||||
/// @param arguments Va arguments.
|
||||
void log(const char *format, ...) noexcept;
|
||||
} // namespace logger
|
||||
11
include/mathutil.hpp
Normal file
11
include/mathutil.hpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
namespace math
|
||||
{
|
||||
template <typename Type>
|
||||
class Util
|
||||
{
|
||||
public:
|
||||
static inline Type absolute_distance(Type a, Type b) noexcept { return a > b ? a - b : b - a; }
|
||||
};
|
||||
}
|
||||
34
include/remote/Form.hpp
Normal file
34
include/remote/Form.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace remote
|
||||
{
|
||||
/// @brief This is a class to build URL encoded form bodies and be more readable than snprintfs.
|
||||
class Form
|
||||
{
|
||||
public:
|
||||
Form() = default;
|
||||
|
||||
/// @brief Appends a parameter to the form/URL encoded text.
|
||||
/// @param param Parameter to append.
|
||||
/// @param value Value to append.
|
||||
Form &append_parameter(std::string_view param, std::string_view value) noexcept;
|
||||
|
||||
/// @brief Returns m_form.length()
|
||||
size_t length() const noexcept;
|
||||
|
||||
/// @brief Returns m_formBuffer;
|
||||
/// @return
|
||||
const char *get() const noexcept;
|
||||
|
||||
private:
|
||||
/// @brief Size used for the buffer.
|
||||
static inline constexpr size_t SIZE_FORM_BUFFER = 0x800;
|
||||
|
||||
/// @brief Current offset if the form.
|
||||
size_t m_offset{};
|
||||
|
||||
/// @brief Buffer for the form.
|
||||
char m_formBuffer[SIZE_FORM_BUFFER] = {0};
|
||||
};
|
||||
} // namespace remote
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user