Skip to content

Commit 0659c48

Browse files
rajveermalviyagnprice
authored andcommitted
binding: Support more device/os variants for deviceInfo getter
1 parent 9031c66 commit 0659c48

File tree

3 files changed

+86
-7
lines changed

3 files changed

+86
-7
lines changed

lib/model/binding.dart

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,13 +161,21 @@ abstract class BaseDeviceInfo {
161161

162162
/// Like [device_info_plus.AndroidDeviceInfo], but without things we don't use.
163163
class AndroidDeviceInfo extends BaseDeviceInfo {
164+
/// The Android version string, Build.VERSION.RELEASE, e.g. "14".
165+
///
166+
/// Upstream documents this as an opaque string with no particular structure,
167+
/// but e.g. on stock Android 14 it's "14".
168+
///
169+
/// See: https://developer.android.com/reference/android/os/Build.VERSION#RELEASE
170+
final String release;
171+
164172
/// The Android SDK version.
165173
///
166174
/// Possible values are defined in:
167175
/// https://developer.android.com/reference/android/os/Build.VERSION_CODES.html
168176
final int sdkInt;
169177

170-
AndroidDeviceInfo({required this.sdkInt});
178+
AndroidDeviceInfo({required this.release, required this.sdkInt});
171179
}
172180

173181
/// Like [device_info_plus.IosDeviceInfo], but without things we don't use.
@@ -180,6 +188,70 @@ class IosDeviceInfo extends BaseDeviceInfo {
180188
IosDeviceInfo({required this.systemVersion});
181189
}
182190

191+
/// Like [device_info_plus.MacOsDeviceInfo], but without things we don't use.
192+
class MacOsDeviceInfo extends BaseDeviceInfo {
193+
/// See: https://developer.apple.com/documentation/foundation/operatingsystemversion/1414662-majorversion
194+
final int majorVersion;
195+
196+
/// See: https://developer.apple.com/documentation/foundation/operatingsystemversion/1413801-minorversion
197+
final int minorVersion;
198+
199+
/// See: https://developer.apple.com/documentation/foundation/operatingsystemversion/1415564-patchversion
200+
final int patchVersion;
201+
202+
MacOsDeviceInfo({
203+
required this.majorVersion,
204+
required this.minorVersion,
205+
required this.patchVersion,
206+
});
207+
}
208+
209+
/// Like [device_info_plus.WindowsDeviceInfo], currently only used to
210+
/// determine if we're on Windows.
211+
// TODO Determine a method to identify the Windows version.
212+
// Currently, we do not include Windows version information because
213+
// Windows OS does not provide a straightforward way to obtain
214+
// recognizable version information.
215+
// Here's an example of `WindowsDeviceInfo` data[1]. Based on that
216+
// data, there are two possible approaches to identify the Windows
217+
// version:
218+
// - One approach is to use a combination of the majorVersion,
219+
// minorVersion, and buildNumber fields. However, this data does
220+
// not directly correspond to recognizable Windows versions
221+
// (for example major=10, minor=0, build=22631 actually represents
222+
// "Windows 11, 23H2"). Refer to the link in this comment[2] for
223+
// Chromium's implementation of parsing Windows version numbers.
224+
// - Another approach is to use the productName field. While this
225+
// field contains the Windows version, it also includes extraneous
226+
// information. For example, some productName strings are:
227+
// "Windows 11 Pro" and "Windows 10 Home Single Language", which
228+
// makes it less ideal.
229+
// [1]: https://gist.github.com/rajveermalviya/58b3add437280cc7f8356f3697099b7c
230+
// [2]: https://github.com/zulip/zulip-flutter/pull/724#discussion_r1628318991
231+
class WindowsDeviceInfo implements BaseDeviceInfo {}
232+
233+
/// Like [device_info_plus.LinuxDeviceInfo], but without things we don't use.
234+
class LinuxDeviceInfo implements BaseDeviceInfo {
235+
/// The operating system name, 'NAME' field in /etc/os-release.
236+
///
237+
/// Examples: 'Fedora', 'Debian GNU/Linux', or just 'Linux'.
238+
///
239+
/// See: https://www.freedesktop.org/software/systemd/man/latest/os-release.html#NAME=
240+
final String name;
241+
242+
/// The operating system version, 'VERSION_ID' field in /etc/os-release.
243+
///
244+
/// This string contains only the version number and excludes the
245+
/// OS name and version codenames.
246+
///
247+
/// Examples: '17', '11.04'.
248+
///
249+
/// See: https://www.freedesktop.org/software/systemd/man/latest/os-release.html#VERSION_ID=
250+
final String? versionId;
251+
252+
LinuxDeviceInfo({required this.name, required this.versionId});
253+
}
254+
183255
/// Like [package_info_plus.PackageInfo], but without things we don't use.
184256
class PackageInfo {
185257
final String version;
@@ -251,9 +323,16 @@ class LiveZulipBinding extends ZulipBinding {
251323
try {
252324
final info = await device_info_plus.DeviceInfoPlugin().deviceInfo;
253325
_syncDeviceInfo = switch (info) {
254-
device_info_plus.AndroidDeviceInfo(:var version) => AndroidDeviceInfo(sdkInt: version.sdkInt),
255-
device_info_plus.IosDeviceInfo(:var systemVersion) => IosDeviceInfo(systemVersion: systemVersion),
256-
_ => throw UnimplementedError(),
326+
device_info_plus.AndroidDeviceInfo() => AndroidDeviceInfo(release: info.version.release,
327+
sdkInt: info.version.sdkInt),
328+
device_info_plus.IosDeviceInfo() => IosDeviceInfo(systemVersion: info.systemVersion),
329+
device_info_plus.MacOsDeviceInfo() => MacOsDeviceInfo(majorVersion: info.majorVersion,
330+
minorVersion: info.minorVersion,
331+
patchVersion: info.patchVersion),
332+
device_info_plus.WindowsDeviceInfo() => WindowsDeviceInfo(),
333+
device_info_plus.LinuxDeviceInfo() => LinuxDeviceInfo(name: info.name,
334+
versionId: info.versionId),
335+
_ => throw UnimplementedError(),
257336
};
258337
} catch (e, st) {
259338
assert(debugLog('Failed to prefetch device info: $e\n$st')); // TODO(log)

test/model/binding.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ class TestZulipBinding extends ZulipBinding {
207207

208208
/// The value that `ZulipBinding.instance.deviceInfo` should return.
209209
BaseDeviceInfo deviceInfoResult = _defaultDeviceInfoResult;
210-
static final _defaultDeviceInfoResult = AndroidDeviceInfo(sdkInt: 33);
210+
static final _defaultDeviceInfoResult = AndroidDeviceInfo(sdkInt: 33, release: '13');
211211

212212
void _resetDeviceInfo() {
213213
deviceInfoResult = _defaultDeviceInfoResult;

test/widgets/clipboard_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@ void main() {
6565
});
6666

6767
testWidgets('Android', (WidgetTester tester) async {
68-
testBinding.deviceInfoResult = AndroidDeviceInfo(sdkInt: 33);
68+
testBinding.deviceInfoResult = AndroidDeviceInfo(sdkInt: 33, release: '13');
6969
await call(tester, text: 'asdf');
7070
await checkClipboardText('asdf');
7171
await checkSnackBar(tester, expected: false);
7272
});
7373

7474
testWidgets('Android <13', (WidgetTester tester) async {
75-
testBinding.deviceInfoResult = AndroidDeviceInfo(sdkInt: 32);
75+
testBinding.deviceInfoResult = AndroidDeviceInfo(sdkInt: 32, release: '12');
7676
await call(tester, text: 'asdf');
7777
await checkClipboardText('asdf');
7878
await checkSnackBar(tester, expected: true);

0 commit comments

Comments
 (0)