提交 23f5ccd2 编写于 作者: Y Yegor 提交者: GitHub

Add alwaysUse24HourFormat and textScaleFactor (#4202)

* systems/settings channel split

* merge textScaleFactor and alwaysUse24HourFormat into flutter/settings channel

* add debugOverrideAlwaysUse24HourFormat

* implement textScaleFactor on iOS

* address comments

* remove debugOverrideAlwaysUse24HourFormat

* clang-format
上级 d3ebce9c
......@@ -32,11 +32,21 @@ void _updateLocale(String languageCode, String countryCode) {
_invoke(window.onLocaleChanged, window._onLocaleChangedZone);
}
void _updateUserSettingsData(String json) {
final Map<String, dynamic> data = JSON.decode(json);
_updateTextScaleFactor(data['textScaleFactor'].toDouble());
_updateAlwaysUse24HourFormat(data['alwaysUse24HourFormat']);
}
void _updateTextScaleFactor(double textScaleFactor) {
window._textScaleFactor = textScaleFactor;
_invoke(window.onTextScaleFactorChanged, window._onTextScaleFactorChangedZone);
}
void _updateAlwaysUse24HourFormat(bool alwaysUse24HourFormat) {
window._alwaysUse24HourFormat = alwaysUse24HourFormat;
}
void _updateSemanticsEnabled(bool enabled) {
window._semanticsEnabled = enabled;
_invoke(window.onSemanticsEnabledChanged, window._onSemanticsEnabledChangedZone);
......
......@@ -269,6 +269,13 @@ class Window {
double get textScaleFactor => _textScaleFactor;
double _textScaleFactor = 1.0;
/// The setting indicating whether time should always be shown in the 24-hour
/// format.
///
/// This option is used by [showTimePicker].
bool get alwaysUse24HourFormat => _alwaysUse24HourFormat;
bool _alwaysUse24HourFormat = false;
/// A callback that is invoked whenever [textScaleFactor] changes value.
///
/// The framework invokes this callback in the same zone in which the
......
......@@ -163,15 +163,15 @@ void Window::UpdateLocale(const std::string& language_code,
});
}
void Window::UpdateTextScaleFactor(double text_scale_factor) {
void Window::UpdateUserSettingsData(const std::string& data) {
tonic::DartState* dart_state = library_.dart_state().get();
if (!dart_state)
return;
tonic::DartState::Scope scope(dart_state);
DartInvokeField(library_.value(), "_updateTextScaleFactor",
DartInvokeField(library_.value(), "_updateUserSettingsData",
{
ToDart(static_cast<double>(text_scale_factor)),
StdStringToDart(data),
});
}
......
......@@ -45,7 +45,7 @@ class Window {
void UpdateWindowMetrics(const ViewportMetrics& metrics);
void UpdateLocale(const std::string& language_code,
const std::string& country_code);
void UpdateTextScaleFactor(double text_scale_factor);
void UpdateUserSettingsData(const std::string& data);
void UpdateSemanticsEnabled(bool enabled);
void DispatchPlatformMessage(fxl::RefPtr<PlatformMessage> message);
void DispatchPointerDataPacket(const PointerDataPacket& packet);
......
......@@ -66,11 +66,11 @@ void RuntimeController::SetLocale(const std::string& language_code,
GetWindow()->UpdateLocale(language_code_, country_code_);
}
void RuntimeController::SetTextScaleFactor(double text_scale_factor) {
if (text_scale_factor_ == text_scale_factor)
void RuntimeController::SetUserSettingsData(const std::string& data) {
if (user_settings_data_ == data)
return;
text_scale_factor_ = text_scale_factor;
GetWindow()->UpdateTextScaleFactor(text_scale_factor_);
user_settings_data_ = data;
GetWindow()->UpdateUserSettingsData(user_settings_data_);
}
void RuntimeController::SetSemanticsEnabled(bool enabled) {
......
......@@ -35,7 +35,7 @@ class RuntimeController : public WindowClient, public IsolateClient {
void SetViewportMetrics(const ViewportMetrics& metrics);
void SetLocale(const std::string& language_code,
const std::string& country_code);
void SetTextScaleFactor(double textScaleFactor);
void SetUserSettingsData(const std::string& data);
void SetSemanticsEnabled(bool enabled);
void BeginFrame(fxl::TimePoint frame_time);
......@@ -66,7 +66,7 @@ class RuntimeController : public WindowClient, public IsolateClient {
RuntimeDelegate* client_;
std::string language_code_;
std::string country_code_;
double text_scale_factor_ = 1.0;
std::string user_settings_data_ = "{}";
bool semantics_enabled_ = false;
std::unique_ptr<DartController> dart_controller_;
......
......@@ -44,7 +44,7 @@ constexpr char kAssetChannel[] = "flutter/assets";
constexpr char kLifecycleChannel[] = "flutter/lifecycle";
constexpr char kNavigationChannel[] = "flutter/navigation";
constexpr char kLocalizationChannel[] = "flutter/localization";
constexpr char kSystemChannel[] = "flutter/system";
constexpr char kSettingsChannel[] = "flutter/settings";
bool PathExists(const std::string& path) {
return access(path.c_str(), R_OK) == 0;
......@@ -75,7 +75,7 @@ Engine::Engine(PlatformView* platform_view)
platform_view->GetVsyncWaiter(),
this)),
load_script_error_(tonic::kNoError),
text_scale_factor_(1.0),
user_settings_data_("{}"),
activity_running_(false),
have_surface_(false),
weak_factory_(this) {}
......@@ -337,11 +337,9 @@ void Engine::DispatchPlatformMessage(
} else if (message->channel() == kLocalizationChannel) {
if (HandleLocalizationPlatformMessage(message.get()))
return;
} else if (message->channel() == kSystemChannel) {
// This only handles textScaleFactor changes: other system messages are
// handled by DispatchPlatformMessage below.
if (HandleSystemPlatformMessage(message.get()))
return;
} else if (message->channel() == kSettingsChannel) {
HandleSettingsPlatformMessage(message.get());
return;
}
if (runtime_) {
......@@ -424,35 +422,15 @@ bool Engine::HandleLocalizationPlatformMessage(
return true;
}
bool Engine::HandleSystemPlatformMessage(blink::PlatformMessage* message) {
void Engine::HandleSettingsPlatformMessage(blink::PlatformMessage* message) {
const auto& data = message->data();
rapidjson::Document document;
document.Parse(reinterpret_cast<const char*>(data.data()), data.size());
if (document.HasParseError() || !document.IsObject())
return false;
auto root = document.GetObject();
auto type = root.FindMember("type");
if (type == root.MemberEnd() || type->value != "systemSettings")
return false;
// This only handles textScaleFactor changes: other system messages
// are handled by DispatchPlatformMessage.
auto text_scale_factor = root.FindMember("textScaleFactor");
if (text_scale_factor == root.MemberEnd() ||
!text_scale_factor->value.IsDouble()) {
return false;
}
text_scale_factor_ = text_scale_factor->value.GetDouble();
std::string jsonData(reinterpret_cast<const char*>(data.data()), data.size());
user_settings_data_ = jsonData;
if (runtime_) {
runtime_->SetTextScaleFactor(text_scale_factor_);
runtime_->SetUserSettingsData(user_settings_data_);
if (have_surface_)
ScheduleFrame();
}
// If the only members were "type" and "textScaleFactor", then we're done.
// If there are more members, then we need to send it on to other handlers.
return root.MemberCount() == 2;
}
void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet) {
......@@ -507,7 +485,7 @@ void Engine::ConfigureRuntime(const std::string& script_uri,
default_isolate_snapshot_instr, platform_kernel);
runtime_->SetViewportMetrics(viewport_metrics_);
runtime_->SetLocale(language_code_, country_code_);
runtime_->SetTextScaleFactor(text_scale_factor_);
runtime_->SetUserSettingsData(user_settings_data_);
runtime_->SetSemanticsEnabled(semantics_enabled_);
}
}
......
......@@ -97,7 +97,7 @@ class Engine : public blink::RuntimeDelegate {
bool HandleNavigationPlatformMessage(
fxl::RefPtr<blink::PlatformMessage> message);
bool HandleLocalizationPlatformMessage(blink::PlatformMessage* message);
bool HandleSystemPlatformMessage(blink::PlatformMessage* message);
void HandleSettingsPlatformMessage(blink::PlatformMessage* message);
void HandleAssetPlatformMessage(fxl::RefPtr<blink::PlatformMessage> message);
bool GetAssetAsBuffer(const std::string& name, std::vector<uint8_t>* data);
......@@ -112,7 +112,7 @@ class Engine : public blink::RuntimeDelegate {
blink::ViewportMetrics viewport_metrics_;
std::string language_code_;
std::string country_code_;
double text_scale_factor_;
std::string user_settings_data_;
bool semantics_enabled_ = false;
// TODO(abarth): Unify these two behind a common interface.
fxl::RefPtr<blink::ZipAssetStore> asset_store_;
......
......@@ -17,6 +17,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Matrix;
import android.os.Build;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
......@@ -101,6 +102,7 @@ public class FlutterView extends SurfaceView
private final BasicMessageChannel<Object> mFlutterKeyEventChannel;
private final BasicMessageChannel<String> mFlutterLifecycleChannel;
private final BasicMessageChannel<Object> mFlutterSystemChannel;
private final BasicMessageChannel<Object> mFlutterSettingsChannel;
private final BroadcastReceiver mDiscoveryReceiver;
private final List<ActivityLifecycleListener> mActivityLifecycleListeners;
private final List<FirstFrameListener> mFirstFrameListeners;
......@@ -173,6 +175,8 @@ public class FlutterView extends SurfaceView
StringCodec.INSTANCE);
mFlutterSystemChannel = new BasicMessageChannel<>(this, "flutter/system",
JSONMessageCodec.INSTANCE);
mFlutterSettingsChannel = new BasicMessageChannel<>(this, "flutter/settings",
JSONMessageCodec.INSTANCE);
// TODO(plugins): Change PlatformPlugin to accept a Context. Disable the
// operations that require an Activity when a Context is passed.
......@@ -186,7 +190,7 @@ public class FlutterView extends SurfaceView
mTextInputPlugin = new TextInputPlugin(this);
setLocale(getResources().getConfiguration().locale);
setTextScaleFactor(getResources().getConfiguration().fontScale);
setUserSettings();
if ((context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
mDiscoveryReceiver = new DiscoveryReceiver();
......@@ -284,11 +288,11 @@ public class FlutterView extends SurfaceView
mFlutterNavigationChannel.invokeMethod("popRoute", null);
}
private void setTextScaleFactor(float textScaleFactor) {
private void setUserSettings() {
Map<String, Object> message = new HashMap<>();
message.put("type", "systemSettings");
message.put("textScaleFactor", textScaleFactor);
mFlutterSystemChannel.send(message);
message.put("textScaleFactor", getResources().getConfiguration().fontScale);
message.put("alwaysUse24HourFormat", DateFormat.is24HourFormat(getContext()));
mFlutterSettingsChannel.send(message);
}
private void setLocale(Locale locale) {
......@@ -300,7 +304,7 @@ public class FlutterView extends SurfaceView
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setLocale(newConfig.locale);
setTextScaleFactor(newConfig.fontScale);
setUserSettings();
}
float getDevicePixelRatio() {
......
......@@ -72,6 +72,7 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse {
fml::scoped_nsprotocol<FlutterMethodChannel*> _textInputChannel;
fml::scoped_nsprotocol<FlutterBasicMessageChannel*> _lifecycleChannel;
fml::scoped_nsprotocol<FlutterBasicMessageChannel*> _systemChannel;
fml::scoped_nsprotocol<FlutterBasicMessageChannel*> _settingsChannel;
fml::scoped_nsprotocol<UIView*> _launchView;
bool _platformSupportsTouchTypes;
bool _platformSupportsTouchPressure;
......@@ -177,6 +178,11 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse {
binaryMessenger:self
codec:[FlutterJSONMessageCodec sharedInstance]]);
_settingsChannel.reset([[FlutterBasicMessageChannel alloc]
initWithName:@"flutter/settings"
binaryMessenger:self
codec:[FlutterJSONMessageCodec sharedInstance]]);
_platformPlugin.reset([[FlutterPlatformPlugin alloc] init]);
[_platformChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
[_platformPlugin.get() handleMethodCall:call result:result];
......@@ -247,6 +253,11 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse {
selector:@selector(onMemoryWarning:)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
[center addObserver:self
selector:@selector(onUserSettingsChanged:)
name:UIContentSizeCategoryDidChangeNotification
object:nil];
}
- (void)setInitialRoute:(NSString*)route {
......@@ -340,6 +351,7 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse {
- (void)viewDidAppear:(BOOL)animated {
TRACE_EVENT0("flutter", "viewDidAppear");
[self onLocaleUpdated:nil];
[self onUserSettingsChanged:nil];
[self onVoiceOverChanged:nil];
[_lifecycleChannel.get() sendMessage:@"AppLifecycleState.resumed"];
......@@ -693,6 +705,60 @@ static inline blink::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* to
[_localizationChannel.get() invokeMethod:@"setLocale" arguments:@[ languageCode, countryCode ]];
}
#pragma mark - Set user settings
- (void)onUserSettingsChanged:(NSNotification*)notification {
[_settingsChannel.get() sendMessage:@{
@"textScaleFactor" : @([self textScaleFactor]),
@"alwaysUse24HourFormat" : @([self isAlwaysUse24HourFormat]),
}];
}
- (CGFloat)textScaleFactor {
UIContentSizeCategory category = [UIApplication sharedApplication].preferredContentSizeCategory;
// The delta is computed based on the following:
// - L (large) is the default 1.0 scale.
// - The scale is linear spanning from XS to XXXL.
// - XXXL = 1.4 * XS.
//
// L = 1.0 = XS + 3 * delta
// XXXL = 1.4 * XS = XS + 6 * delta
const CGFloat delta = 0.055555;
if ([category isEqualToString:UIContentSizeCategoryExtraSmall])
return 1.0 - 3 * delta;
else if ([category isEqualToString:UIContentSizeCategorySmall])
return 1.0 - 2 * delta;
else if ([category isEqualToString:UIContentSizeCategoryMedium])
return 1.0 - delta;
else if ([category isEqualToString:UIContentSizeCategoryLarge])
return 1.0;
else if ([category isEqualToString:UIContentSizeCategoryExtraLarge])
return 1.0 + delta;
else if ([category isEqualToString:UIContentSizeCategoryExtraExtraLarge])
return 1.0 + 2 * delta;
else if ([category isEqualToString:UIContentSizeCategoryExtraExtraExtraLarge])
return 1.0 + 3 * delta;
else
return 1.0;
}
- (BOOL)isAlwaysUse24HourFormat {
// iOS does not report its "24-Hour Time" user setting in the API. Instead, it applies
// it automatically to NSDateFormatter when used with [NSLocale currentLocale]. It is
// essential that [NSLocale currentLocale] is used. Any custom locale, even the one
// that's the same as [NSLocale currentLocale] will ignore the 24-hour option (there
// must be some internal field that's not exposed to developers).
//
// Therefore this option behaves differently across Android and iOS. On Android this
// setting is exposed standalone, and can therefore be applied to all locales, whether
// the "current system locale" or a custom one. On iOS it only applies to the current
// system locale. Widget implementors must take this into account in order to provide
// platform-idiomatic behavior in their widgets.
NSString* dateFormat =
[NSDateFormatter dateFormatFromTemplate:@"j" options:0 locale:[NSLocale currentLocale]];
return [dateFormat rangeOfString:@"a"].location == NSNotFound;
}
#pragma mark - Status Bar touch event handling
// Standard iOS status bar height in pixels.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册