Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some improvements for hiding/locking apps #164

Merged
merged 17 commits into from
Sep 25, 2024
53 changes: 53 additions & 0 deletions LiveContainerSwiftUI/LCAppBanner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ struct LCAppBanner : View {
Capsule().fill(Color("JITBadgeColor"))
)
}
if model.uiIsLocked && !model.uiIsHidden {
Text("lc.appBanner.locked".loc).font(.system(size: 8)).bold().padding(2)
.frame(width: 50, height:16)
.background(
Capsule().fill(Color("BadgeColor"))
)
}
}

Text("\(appInfo.version()) - \(appInfo.bundleIdentifier())").font(.system(size: 12)).foregroundColor(Color("FontColor"))
Expand Down Expand Up @@ -239,6 +246,18 @@ struct LCAppBanner : View {
}

func runApp() async {
if appInfo.isLocked && !sharedModel.isHiddenAppUnlocked {
do {
if !(try await LCUtils.authenticateUser()) {
return
}
} catch {
errorInfo = error.localizedDescription
errorShow = true
return
}
}

do {
try await model.runApp()
} catch {
Expand Down Expand Up @@ -319,3 +338,37 @@ struct LCAppBanner : View {


}


struct LCAppSkeletonBanner: View {
var body: some View {
HStack {
RoundedRectangle(cornerRadius: 12)
.fill(Color.gray.opacity(0.3))
.frame(width: 60, height: 60)

VStack(alignment: .leading, spacing: 5) {
RoundedRectangle(cornerRadius: 4)
.fill(Color.gray.opacity(0.3))
.frame(width: 100, height: 16)

RoundedRectangle(cornerRadius: 4)
.fill(Color.gray.opacity(0.3))
.frame(width: 150, height: 12)

RoundedRectangle(cornerRadius: 4)
.fill(Color.gray.opacity(0.3))
.frame(width: 120, height: 8)
}

Spacer()

RoundedRectangle(cornerRadius: 16)
.fill(Color.gray.opacity(0.3))
.frame(width: 70, height: 32)
}
.padding()
.frame(height: 88)
.background(RoundedRectangle(cornerRadius: 22).fill(Color.gray.opacity(0.1)))
}
}
92 changes: 59 additions & 33 deletions LiveContainerSwiftUI/LCAppListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct LCAppListView : View, LCAppBannerDelegate, LCAppModelDelegate {
@State private var isNavigationActive = false

@EnvironmentObject private var sharedModel : SharedModel

init(apps: Binding<[LCAppModel]>, hiddenApps: Binding<[LCAppModel]>, appDataFolderNames: Binding<[String]>, tweakFolderNames: Binding<[String]>) {
_installOptions = State(initialValue: [])
_apps = apps
Expand Down Expand Up @@ -95,38 +95,61 @@ struct LCAppListView : View, LCAppBannerDelegate, LCAppModelDelegate {
}
.padding()
.animation(.easeInOut, value: apps)

if !sharedModel.isHiddenAppUnlocked {
Text(apps.count > 0 ? "lc.appList.appCounter %lld".localizeWithFormat(apps.count) : "lc.appList.installTip".loc).foregroundStyle(.gray)
.onTapGesture(count: 3) {
Task { await authenticateUser() }
}
}


if sharedModel.isHiddenAppUnlocked {
LazyVStack {
HStack {
Text("lc.appList.hiddenApps".loc)
.font(.system(.title2).bold())
.border(Color.black)
Spacer()
VStack {
if LCUtils.appGroupUserDefault.bool(forKey: "LCStrictHiding") {
if sharedModel.isHiddenAppUnlocked {
LazyVStack {
HStack {
Text("lc.appList.hiddenApps".loc)
.font(.system(.title2).bold())
Spacer()
}
ForEach(hiddenApps, id: \.self) { app in
LCAppBanner(appModel: app, delegate: self, appDataFolders: $appDataFolderNames, tweakFolders: $tweakFolderNames)
}
}
.padding()
.transition(.opacity)
.animation(.easeInOut, value: apps)

if hiddenApps.count == 0 {
Text("lc.appList.hideAppTip".loc)
.foregroundStyle(.gray)
}
}
ForEach(hiddenApps, id: \.self) { app in
LCAppBanner(appModel: app, delegate: self, appDataFolders: $appDataFolderNames, tweakFolders: $tweakFolderNames)
} else if hiddenApps.count > 0 {
LazyVStack {
HStack {
Text("lc.appList.hiddenApps".loc)
.font(.system(.title2).bold())
Spacer()
}
ForEach(hiddenApps, id: \.self) { app in
if sharedModel.isHiddenAppUnlocked {
LCAppBanner(appModel: app, delegate: self, appDataFolders: $appDataFolderNames, tweakFolders: $tweakFolderNames)
} else {
LCAppSkeletonBanner()
}
}
.animation(.easeInOut, value: sharedModel.isHiddenAppUnlocked)
.onTapGesture {
Task { await authenticateUser() }
}
}
.transition(.scale)
.padding()
.animation(.easeInOut, value: apps)
}
.padding()
.animation(.easeInOut, value: apps)

if hiddenApps.count == 0 {
Text("lc.appList.hideAppTip".loc)
.foregroundStyle(.gray)
}
Text(apps.count + hiddenApps.count > 0 ? "lc.appList.appCounter %lld".localizeWithFormat(apps.count + hiddenApps.count) : "lc.appList.installTip".loc).foregroundStyle(.gray)
}

let appCount = sharedModel.isHiddenAppUnlocked ? apps.count + hiddenApps.count : apps.count
Text(appCount > 0 ? "lc.appList.appCounter %lld".localizeWithFormat(appCount) : "lc.appList.installTip".loc)
.foregroundStyle(.gray)
.animation(.easeInOut, value: appCount)
.onTapGesture(count: 3) {
Task { await authenticateUser() }
}
}.animation(.easeInOut, value: LCUtils.appGroupUserDefault.bool(forKey: "LCStrictHiding"))

if LCUtils.multiLCStatus == 2 {
Text("lc.appList.manageInPrimaryTip".loc).foregroundStyle(.gray).padding()
}
Expand Down Expand Up @@ -272,7 +295,7 @@ struct LCAppListView : View, LCAppBannerDelegate, LCAppModelDelegate {
return
}

if appToLaunch.appInfo.isHidden && !sharedModel.isHiddenAppUnlocked {
if appToLaunch.appInfo.isLocked && !sharedModel.isHiddenAppUnlocked {
do {
if !(try await LCUtils.authenticateUser()) {
return
Expand Down Expand Up @@ -460,24 +483,27 @@ struct LCAppListView : View, LCAppBannerDelegate, LCAppModelDelegate {
return
}
var appFound : LCAppModel? = nil
var isFoundAppHidden = false
var isFoundAppLocked = false
for app in apps {
if app.appInfo.relativeBundlePath == bundleId {
appFound = app
if app.appInfo.isLocked {
isFoundAppLocked = true
}
break
}
}
if appFound == nil && !LCUtils.appGroupUserDefault.bool(forKey: "LCStrictHiding") {
for app in hiddenApps {
if app.appInfo.relativeBundlePath == bundleId {
appFound = app
isFoundAppHidden = true
isFoundAppLocked = true
break
}
}
}

if isFoundAppHidden && !sharedModel.isHiddenAppUnlocked {
if isFoundAppLocked && !sharedModel.isHiddenAppUnlocked {
do {
let result = try await LCUtils.authenticateUser()
if !result {
Expand Down
20 changes: 20 additions & 0 deletions LiveContainerSwiftUI/LCAppModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class LCAppModel: ObservableObject, Hashable {

@Published var uiIsJITNeeded : Bool
@Published var uiIsHidden : Bool
@Published var uiIsLocked : Bool
@Published var uiIsShared : Bool
@Published var uiDataFolder : String?
@Published var uiTweakFolder : String?
Expand All @@ -29,9 +30,14 @@ class LCAppModel: ObservableObject, Hashable {
init(appInfo : LCAppInfo, delegate: LCAppModelDelegate? = nil) {
self.appInfo = appInfo
self.delegate = delegate

if !appInfo.isLocked && appInfo.isHidden {
appInfo.isLocked = true
}

self.uiIsJITNeeded = appInfo.isJITNeeded
self.uiIsHidden = appInfo.isHidden
self.uiIsLocked = appInfo.isLocked
self.uiIsShared = appInfo.isShared
self.uiDataFolder = appInfo.getDataUUIDNoAssign()
self.uiTweakFolder = appInfo.tweakFolder()
Expand Down Expand Up @@ -121,6 +127,20 @@ class LCAppModel: ObservableObject, Hashable {
LCUtils.launchToGuestApp()

}

func toggleLock() async {
if appInfo.isLocked {
appInfo.isLocked = false
uiIsLocked = false

if appInfo.isHidden {
await toggleHidden()
}
} else {
appInfo.isLocked = true
uiIsLocked = true
}
}

func toggleHidden() async {
delegate?.closeNavigationView()
Expand Down
37 changes: 31 additions & 6 deletions LiveContainerSwiftUI/LCAppSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -153,20 +153,45 @@ struct LCAppSettingsView : View{
} footer: {
Text("lc.appSettings.launchWithJitDesc".loc)
}

if sharedModel.isHiddenAppUnlocked {
Section {

Section {
Toggle(isOn: $model.uiIsLocked) {
Text("lc.appSettings.lockApp".loc)
}
.onChange(of: model.uiIsLocked, perform: { newValue in
Task {
if !newValue {
do {
let result = try await LCUtils.authenticateUser()
if !result {
model.uiIsLocked = true
return
}
} catch {
return
}
}

await model.toggleLock()
}
})

if model.uiIsLocked {
Toggle(isOn: $model.uiIsHidden) {
Text("lc.appSettings.hideApp".loc)
}
.onChange(of: model.uiIsHidden, perform: { newValue in
.onChange(of: model.uiIsHidden, perform: { _ in
Task { await toggleHidden() }
})
} footer: {
.transition(.opacity.combined(with: .slide))
}
} footer: {
if model.uiIsLocked {
Text("lc.appSettings.hideAppDesc".loc)
.transition(.opacity.combined(with: .slide))
}

}


Section {
Toggle(isOn: $model.uiDoSymlinkInbox) {
Expand Down
12 changes: 5 additions & 7 deletions LiveContainerSwiftUI/LCSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,12 @@ struct LCSettingsView: View {
Text("lc.settings.injectLCItselfDesc".loc)
}

if sharedModel.isHiddenAppUnlocked {
Section {
Toggle(isOn: $strictHiding) {
Text("lc.settings.strictHiding".loc)
}
} footer: {
Text("lc.settings.strictHidingDesc".loc)
Section {
Toggle(isOn: $strictHiding) {
Text("lc.settings.strictHiding".loc)
}
} footer: {
Text("lc.settings.strictHidingDesc".loc)
}

Section {
Expand Down
4 changes: 2 additions & 2 deletions LiveContainerSwiftUI/LCWebView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ struct LCWebView: View {
return
}

if appToLaunch.appInfo.isHidden && !sharedModel.isHiddenAppUnlocked {
if appToLaunch.appInfo.isLocked && !sharedModel.isHiddenAppUnlocked {

do {
if !(try await LCUtils.authenticateUser()) {
Expand Down Expand Up @@ -214,7 +214,7 @@ struct LCWebView: View {
return
}

if appToLaunch.appInfo.isHidden && !sharedModel.isHiddenAppUnlocked {
if appToLaunch.appInfo.isLocked && !sharedModel.isHiddenAppUnlocked {
do {
if !(try await LCUtils.authenticateUser()) {
return
Expand Down
34 changes: 34 additions & 0 deletions LiveContainerSwiftUI/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,23 @@
}
}
},
"lc.appBanner.locked" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "LOCKED"
}
},
"zh_CN" : {
"stringUnit" : {
"state" : "translated",
"value" : "锁定"
}
}
}
},
"lc.appBanner.uninstall" : {
"extractionState" : "manual",
"localizations" : {
Expand Down Expand Up @@ -790,6 +807,23 @@
}
}
},
"lc.appSettings.lockApp" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Lock App"
}
},
"zh_CN" : {
"stringUnit" : {
"state" : "translated",
"value" : "锁定App"
}
}
}
},
"lc.appSettings.hideApp" : {
"extractionState" : "manual",
"localizations" : {
Expand Down
1 change: 1 addition & 0 deletions LiveContainerUI/LCAppInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@property NSString* relativeBundlePath;
@property bool isShared;
@property bool isJITNeeded;
@property bool isLocked;
@property bool isHidden;
@property bool doSymlinkInbox;
@property bool bypassAssertBarrierOnQueue;
Expand Down
Loading