Provenance-Emu / Provenance

iOS & tvOS multi-emulator frontend, supporting various Atari, Bandai, NEC, Nintendo, Sega, SNK and Sony console systems… Get Started: https://wiki.provenance-emu.com |
https://provenance-emu.com
Other
5.96k stars 689 forks source link

Left bar button items are inaccessible on tvOS #1456

Closed dnicolson closed 2 years ago

dnicolson commented 3 years ago

It is not possible to switch between the filter and import buttons, accessing the left bar buttons is problematic as well. If the conflicts button is visible the import button appears to be unreachable.

### Expected: To be able to navigate to import from the filter button by pressing right. ### Actual: Pressing right shifts focus to the main menu.

Reproduce:

  1. Press down, down and up
  2. Press right

Untitled

APP VERSION

APP SOURCE

INSTALLED BY

PLATFORM

iOS/tvOS VERSION


🚫 We DO NOT support unofficial builds installed from 3rd-party sites. (Official Install)
Need help or have a suggestion? Join our Official Discord

mrjschulte commented 3 years ago

Seems like this is an issue that requires at least 3 titles to be present before one can navigate to them.

cheif commented 3 years ago

I can verify this as well, I had a quick glance at the code and didn't find anything strange, and according to the documentation this should be handled well https://developer.apple.com/documentation/uikit/uinavigationitem/1624946-leftbarbuttonitems (says nothing about avoiding multiple buttons).

We could move one of the buttons to the top-right (that would make it on pair with iOS as well), but I guess the problem would still be there when we get conflicts?

mrjschulte commented 3 years ago

Or, do we go even more extreme and remove all of the buttons and just make the Settings page the place where you do those items. It would be a shame to break that easily accessible tvOS Ux for adding titles but perhaps it's better and clearer (let alone actually usable)?

mrjschulte commented 3 years ago

Any further thoughts on this @dnicolson or @cheif ?

dnicolson commented 3 years ago

I think a Focus Guide may help in this instance, I can't say for sure as tvOS development isn't my forte.

mrjschulte commented 3 years ago

Good suggestion, I'm fairly new at this myself so I'll take a look at this soon based on the teachings here, https://www.enekoalonso.com/articles/understanding-and-visualizing-uifocusguide-on-tvos

mrjschulte commented 3 years ago

Has anyone had a chance to take a stab at this? I've been busy updating the "big 3" cores and might free up for some more time to do the basic Ux stuff soon.

JoeMatt commented 3 years ago

I looked at this for a bit for 2.0.

This really should be working as-is as @cheif stated. We're using 2 barbuttonitems in the navbar for the main tab bar VC in the story board.

This really should 'just work'. It seems like something else is causing issue for tvOS cause I can sometimes get one or the other button by tapping up from the library, or left from the top menu, but can never switch between them.

A focus guide might be necessary. Still weird, cause the collection view uses a pretty basic layout manager that doesn't seem to have any odd code.

There ARE some constraint warnings on tvOS though, that might be the first thing to fix actually.

  1. Fix constraint warnings (using breakpoints, see the console logs from xcode about this)
  2. if 1 fails still, try a focus guide.
dnicolson commented 3 years ago

The constraint warnings don't appear to be related, I don't see any with an empty library.

dnicolson commented 3 years ago

I've done some investigation and not found a solution, maybe the findings will be useful to someone though. Apple states that "Focus moves automatically between buttons in the same row" but it looks like UITabBarController and UINavigationBar compete for focus if at the same vertical position.

With an empty library and two left bar buttons displayed I checked if the left button was focusable by enabling focus logging and with LLDB:

po [UIFocusDebugger checkFocusabilityForItem:0x7fdf1e632c80]
This item should be focusable.

If you are still having trouble focusing this item, consider the following:
 – This tool will not detect if this item is denied focus as the result of returning NO from -shouldUpdateFocusInContext:.
 – This tool will not detect if another item or guide is redirecting focus movement away from this item.
 – This tool may not detect if this item has dynamic conditions that affect its focusability.

I investigated adding a Focus Guide, but the preferredFocusEnvironments value requires an instance of UIView and UIBarButtonItem does not inherit from UIView. You can subclass UIView and add it to the left bar buttons with a customView but that does not appear to work with a Focus Guide.

Adding a shouldUpdateFocus override in PVTVTabBarController resulted in this message when trying to navigate to the left button:

PVTVTabBarController <UIFocusUpdateContext: 0x600001cbe940: previouslyFocusedItem=<UINavigationButton 0x7f9d76658ea0>, nextFocusedItem=<UITabBarButton 0x7f9d7652a5f0>, focusHeading=Left>

It is not finding the UINavigationButton to the left but instead finding UITabBarButton at the top, so it seems to ignore the focus change as it is not to the left.

I then looked at removing existing layout guides, for example removing the one on PVTVTabBarController results in not being able to focus from the UITabBarController to the left bar buttons (the reverse still works though):

view.removeLayoutGuide(view.layoutGuides[0])

There are some other layout guides relating to the navigation bar but removing them seemed to have no effect.

Ultimately, the only way I could select the left button was to do something as horrible as this (and wouldn't work if three buttons were displayed):

override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) {
    super.pressesBegan(presses, with: event)
    if presses.contains(where: { (press) -> Bool in press.type == .leftArrow }) {
        setNeedsFocusUpdate()
    }
}

This resulted in the focus defaulting to the left button:

Provenance[36858:13556285] [FocusDebug] Updating focus from <UINavigationButton 0x7fe6b161caf0> to <UINavigationButton 0x7fe6b152e5b0> in focus system <UIFocusSystem 0x600000aecf50>.

The result of the focus update was determined from the following preferred focus search:
|
|   Starting preferred focus search:
|   |--> Searching <Provenance.PVTVTabBarController 0x7fe682013000>...
|        |--> Searching <UINavigationController 0x7fe682013600>...
|             |--> Searching <Provenance.PVGameLibraryViewController 0x7fe68200bc00>...
|                  |--> Searching <UIView 0x7fe6b15274f0>...
|                       No more preferences for this environment, and there are no focusable items in this environment to prefer by default.
|                  No more preferences for this environment, and there are no focusable items in this environment to prefer by default.
|             |--> Searching <UINavigationBar 0x7fe68160ead0>...
|                  |--> Searching <UINavigationButton 0x7fe6b152e5b0>...
|                       It's focusable!

I then created a basic Storyboard layout and the problem was reproducible with minimal code (Left Bar Buttons.zip). Interestingly, creating the tabs and buttons with code instead resulted in the focus working correctly but the buttons were positioned lower:

self.window = UIWindow(frame: UIScreen.main.bounds)

let vc = ViewController()
vc.tabBarItem.title = "Library"
let vc2 = ViewController()
vc2.tabBarItem.title = "Search"
let vc3 = ViewController()
vc3.tabBarItem.title = "Settings"

let add = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: nil)
let add2 = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: nil)
let add3 = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: nil)
vc.navigationItem.leftBarButtonItems = [add, add2, add3]

let viewControllers = [vc, vc2, vc3].map { UINavigationController(rootViewController: $0)}
viewControllers.forEach { $0.title = $0.viewControllers[0].tabBarItem.title }

let tabBarController = UITabBarController()
tabBarController.viewControllers = viewControllers

self.window?.rootViewController = tabBarController
self.window?.makeKeyAndVisible()

The Debug View Hierarchy appeared to show the same hierarchy for both options, except with the code option the UINavigationBar constraint had a value of navigationBar.minY = 157 instead of navigationBar.minY = 0.

LLDB showed some differences between the two UINavigationBar objects, the barPosition value differed which might explain the top position difference based on iOS screenshots. I did not have any success with altering this value, it doesn't seem like it would solve the overall focus issue either.

mrjschulte commented 3 years ago

Great bit of research on this @dnicolson ! Thanks for diving in, the saga continues!

JoeMatt commented 2 years ago

closed by #1706