@@ -217,8 +217,7 @@ final class AppListModel: ObservableObject {
217217
218218 func rebuildIconCache( ) throws {
219219 // Sadly, we can't call `trollstorehelper` directly because only TrollStore can launch it without error.
220- LSApplicationWorkspace . default ( )
221- . openApplication ( withBundleID: " com.opa334.TrollStore " )
220+ LSApplicationWorkspace . default ( ) . openApplication ( withBundleID: " com.opa334.TrollStore " )
222221 }
223222}
224223
@@ -258,6 +257,80 @@ struct AppListCell: View {
258257 return attributedString
259258 }
260259
260+ @ViewBuilder
261+ var cellContextMenu : some View {
262+ Button {
263+ launch ( )
264+ } label: {
265+ Label ( NSLocalizedString ( " Launch " , comment: " " ) , systemImage: " command " )
266+ }
267+
268+ if isFilzaInstalled {
269+ Button {
270+ openInFilza ( )
271+ } label: {
272+ Label ( NSLocalizedString ( " Show in Filza " , comment: " " ) , systemImage: " scope " )
273+ }
274+ }
275+
276+ if AppListModel . hasTrollStore && app. isAllowedToAttachOrDetach {
277+ if app. isDetached {
278+ Button {
279+ do {
280+ let injector = try Injector ( bundleURL: app. url, teamID: app. teamID)
281+ try injector. setDetached ( false )
282+ withAnimation {
283+ app. reload ( )
284+ AppListModel . shared. isRebuildNeeded = true
285+ }
286+ } catch { DDLogError ( " \( error. localizedDescription) " ) }
287+ } label: {
288+ Label ( NSLocalizedString ( " Unlock Version " , comment: " " ) , systemImage: " lock.open " )
289+ }
290+ } else {
291+ Button {
292+ do {
293+ let injector = try Injector ( bundleURL: app. url, teamID: app. teamID)
294+ try injector. setDetached ( true )
295+ withAnimation {
296+ app. reload ( )
297+ AppListModel . shared. isRebuildNeeded = true
298+ }
299+ } catch { DDLogError ( " \( error. localizedDescription) " ) }
300+ } label: {
301+ Label ( NSLocalizedString ( " Lock Version " , comment: " " ) , systemImage: " lock " )
302+ }
303+ }
304+ }
305+ }
306+
307+ @ViewBuilder
308+ var cellContextMenuWrapper : some View {
309+ if #available( iOS 16 . 0 , * ) {
310+ // iOS 16
311+ cellContextMenu
312+ } else {
313+ if #available( iOS 15 . 0 , * ) { }
314+ else {
315+ // iOS 14
316+ cellContextMenu
317+ }
318+ }
319+ }
320+
321+ @ViewBuilder
322+ var cellBackground : some View {
323+ if #available( iOS 15 . 0 , * ) {
324+ if #available( iOS 16 . 0 , * ) { }
325+ else {
326+ // iOS 15
327+ Color . clear
328+ . contextMenu { cellContextMenu }
329+ . id ( app. isDetached)
330+ }
331+ }
332+ }
333+
261334 var body : some View {
262335 HStack ( spacing: 12 ) {
263336 Image ( uiImage: app. alternateIcon ?? app. icon ?? UIImage ( ) )
@@ -318,56 +391,12 @@ struct AppListCell: View {
318391 }
319392 }
320393 }
321- . contextMenu {
322- Button {
323- launch ( )
324- } label: {
325- Label ( NSLocalizedString ( " Launch " , comment: " " ) , systemImage: " command " )
326- }
327-
328- if isFilzaInstalled {
329- Button {
330- openInFilza ( )
331- } label: {
332- Label ( NSLocalizedString ( " Show in Filza " , comment: " " ) , systemImage: " scope " )
333- }
334- }
335-
336- if AppListModel . hasTrollStore && app. isAllowedToAttachOrDetach {
337- if app. isDetached {
338- Button {
339- do {
340- let injector = try Injector ( bundleURL: app. url, teamID: app. teamID)
341- try injector. setDetached ( false )
342- withAnimation {
343- app. reload ( )
344- AppListModel . shared. isRebuildNeeded = true
345- }
346- } catch { DDLogError ( " \( error. localizedDescription) " ) }
347- } label: {
348- Label ( NSLocalizedString ( " Unlock Version " , comment: " " ) , systemImage: " lock.open " )
349- }
350- } else {
351- Button {
352- do {
353- let injector = try Injector ( bundleURL: app. url, teamID: app. teamID)
354- try injector. setDetached ( true )
355- withAnimation {
356- app. reload ( )
357- AppListModel . shared. isRebuildNeeded = true
358- }
359- } catch { DDLogError ( " \( error. localizedDescription) " ) }
360- } label: {
361- Label ( NSLocalizedString ( " Lock Version " , comment: " " ) , systemImage: " lock " )
362- }
363- }
364- }
365- }
394+ . contextMenu { cellContextMenuWrapper }
395+ . background ( cellBackground)
366396 }
367397
368398 private func launch( ) {
369- LSApplicationWorkspace . default ( )
370- . openApplication ( withBundleID: app. id)
399+ LSApplicationWorkspace . default ( ) . openApplication ( withBundleID: app. id)
371400 }
372401
373402 var isFilzaInstalled : Bool { AppListModel . shared. isFilzaInstalled }
@@ -476,11 +505,6 @@ struct AppListView: View {
476505 . padding ( . vertical, 4 )
477506 }
478507 . disabled ( vm. isRebuilding)
479- } footer: {
480- NavigationLink ( isActive: $isErrorOccurred) {
481- FailureView ( title: NSLocalizedString ( " Error " , comment: " " ) ,
482- message: errorMessage)
483- } label: { }
484508 }
485509 }
486510
@@ -529,6 +553,12 @@ struct AppListView: View {
529553 }
530554 . listStyle ( . insetGrouped)
531555 . navigationTitle ( NSLocalizedString ( " TrollFools " , comment: " " ) )
556+ . background ( Group {
557+ NavigationLink ( isActive: $isErrorOccurred) {
558+ FailureView ( title: NSLocalizedString ( " Error " , comment: " " ) ,
559+ message: errorMessage)
560+ } label: { }
561+ } )
532562 . toolbar {
533563 ToolbarItem ( placement: . navigationBarTrailing) {
534564 Button {
0 commit comments