Repository navigation
Conversation
| /// Label for "search web" edit buttons and menu items. | ||
| String get searchWebButtonLabel; | ||
|
|
||
| /// The term used for presenting a translation menu for a selection. |
There was a problem hiding this comment.
nit: consider changing to Label for "translate" edit buttons and menu items. similar to the other context menu button labels documentation.
|
|
||
| return !widget.obscureText && | ||
| !textEditingValue.selection.isCollapsed && | ||
| textEditingValue.selection.textInside(textEditingValue.text).trim() != ''; |
There was a problem hiding this comment.
I tried on a physical iPhone and was able to get the translate button to show up on a native app (iMessage) if the only text selected was whitespace.
I would usually lean towards matching native even though I don't think translating whitespace adds value here. Definetely not a blocker.
| expect(find.text('Search Web'), findsOneWidget); | ||
|
|
||
| // Adding Translate pushes both Share and Translate to the next page | ||
| // So just check that they exist on the tool bar. |
There was a problem hiding this comment.
nit: tool bar -> toolbar.
| expect(find.text('Search Web'), findsOneWidget); | ||
|
|
||
| // Adding Translate pushes both Share and Translate to the next page | ||
| // So just check that they exist on the tool bar. |
There was a problem hiding this comment.
nit: tool bar -> toolbar.
|
|
||
| // Adding Translate pushes both Share and Translate to the next page | ||
| // So just check that they exist on the tool bar. | ||
| expect(cupertinoToolbarHasText('Share...'), isTrue); |
There was a problem hiding this comment.
Consider using find.text('Translate', skipOffstage: false) instead of using cupertinoToolbarHasText.
| expect(findOverflowNextButton(), findsOneWidget); | ||
|
|
||
| // Tapping the next button again shows the last page and the Share button | ||
| // Tapping the next button again shows the Share button |
There was a problem hiding this comment.
nit: end comments with a ., here and in the comment below.
| @available(iOS 17.4, *) | ||
| fileprivate struct ContentView: View { | ||
| fileprivate let termToTranslate: String | ||
| fileprivate let ipadBounds: CGRect? |
There was a problem hiding this comment.
these 2 are not accessed outside of ContentView so should be private rather than fileprivate
| fileprivate let termToTranslate: String | ||
| fileprivate let ipadBounds: CGRect? | ||
|
|
||
| fileprivate var onDismiss: (() -> Void)? |
There was a problem hiding this comment.
it's file for this to be default (i.e. internal), because the struct itself is already fileprivate
| CGRect lastRect = [(FlutterTextInputView*)_textInputPlugin.textInputView | ||
| caretRectForPosition:(FlutterTextPosition*)range.end]; | ||
| CGRect transformedLastRect = [(FlutterTextInputView*)_textInputPlugin.textInputView | ||
| localRectFromFrameworkTransform:lastRect]; |
There was a problem hiding this comment.
Is this trying to get the bounding boxes of the current selection? So the assumption here is "term" is the same as the selected text? In that case why does the framework have to send "term" over if we know it's going to be the selected text?
| CGRect transformedLastRect = [(FlutterTextInputView*)_textInputPlugin.textInputView | ||
| localRectFromFrameworkTransform:lastRect]; | ||
|
|
||
| // In case of RTL Language, get the minimum x coordinate too |
There was a problem hiding this comment.
I don't think this works in bidi text (I'm not sure if there's a valid use case for selecting across bidi regions, but the UI may look out of place if the user actually does that).
|
|
||
| swiftUIViewController.view.translatesAutoresizingMaskIntoConstraints = false | ||
| NSLayoutConstraint.activate([ | ||
| swiftUIViewController.view.topAnchor.constraint(equalTo: view.topAnchor), |
There was a problem hiding this comment.
So swiftUIViewController can use a different coordinate system even from FlutterView (if topAnchor is not 0 for example), and iPadBounds is calculated in the textInputView's coordinates?
| termToTranslate: termToTranslate, | ||
| ipadBounds: ipadBounds | ||
| ) | ||
| contentView.onDismiss = { [weak self] in |
There was a problem hiding this comment.
Would it be possible to make onDismiss a let variable? Looks like it's not changing.
| swiftUIViewController.didMove(toParent: self) | ||
| } | ||
|
|
||
| @objc func makeTranslateHostingController(termToTranslate: String) -> UIViewController { |
There was a problem hiding this comment.
Why's this method @objc and internal? It seems it's only called in viewDidLoad?
| /// Currently this is only implemented for iOS. | ||
| /// | ||
| /// When 'obscureText' is true or the selection is empty, this function will not do anything. | ||
| Future<void> translateSelection(SelectionChangedCause cause) async { |
There was a problem hiding this comment.
Why does this take a SelectionChangedCause? Doesn't seem to be used anywhere.
There was a problem hiding this comment.
Not very familiar with context menus, but it looks like this is going to be called to trigger translation in a Flutter rendered context menu while the new logic in system_context_menu.dart is going to be used when the app is using an iOS rendered context menu? If that's the case, how does the app developer determine whether translation is available (i.e. the app is running on iOS 17.4+) and hide the button in the translationEnabled implementation (to prevent a "translate" button that does nothing from showing up).
| } | ||
| } | ||
|
|
||
| /// Launch a translation interface for the selected text. |
There was a problem hiding this comment.
nit:
| /// Launch a translation interface for the selected text. | |
| /// Launches a translation interface for the selected text. |
|
|
||
| /// Launch a translation interface for the selected text. | ||
| /// | ||
| /// Currently this is only implemented for iOS. |
There was a problem hiding this comment.
And only for iOS 17.4+ I think?
| #import <OCMock/OCMock.h> | ||
| #import <XCTest/XCTest.h> | ||
|
|
||
| #import "flutter/shell/platform/darwin/common/InternalFlutterSwiftCommon/InternalFlutterSwiftCommon.h" |
There was a problem hiding this comment.
I thought this was the bridging header? Why is the import needed?
| var body: some View { | ||
| Color.clear | ||
| .frame(maxWidth: .infinity, maxHeight: .infinity) | ||
| .translationPresentation( |
There was a problem hiding this comment.
Just curious, is this API only available in SwiftUI?
|
I've marked this PR as not ready to port to flutter/packages yet. The changes not in the material or cupertino libraries will remain here. |
|
Advice for PR splitting: Since this touches material/cupertino along with other parts of flutter/flutter, it will need to be split up. If the material/cupertino changes are dependent on the other non-material/cupertino changes in this PR, then the material/cupertino changes will need to wait for them to roll to stable before they can be ported over to material_ui/cupertino_ui in flutter/packages (which uses the stable branch).
|
|
material_ui and cupertino_ui are now accepting contributions. :) The portions of this PR that affect the material and cupertino libraries can be ported over to flutter/packages, although they may have to wait for the changes in the core SDK to reach stable first. Guidance and instructions for easily porting over can be found in #188444 |
|
Closing in favor of #189878 |
Split out engine portion of flutter#180021 b/c of cupertino/material freeze. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing.
Fixes #150392, part of #107578
This PR adds a "Translate" action to the ios selection context menu using this swiftui translate api announce during WWDC 2024.
Includes the ipad implementation as well.
Simulator.Screen.Recording.-.iPad.Air.11-inch.M3.-.2025-05-28.at.14.11.58.mp4
Simulator.Screen.Recording.-.iPhone.16.Plus.-.2025-05-28.at.14.09.13.mp4
Pre-launch Checklist
///).