Skip to content

Commit

Permalink
feat(bootstrap): set input source via gsettings
Browse files Browse the repository at this point in the history
  • Loading branch information
d-loose committed Apr 11, 2024
1 parent c72429f commit ce55002
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 6 deletions.
35 changes: 33 additions & 2 deletions packages/ubuntu_bootstrap/lib/services/keyboard_service.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import 'package:dbus/dbus.dart';
import 'package:gsettings/gsettings.dart';
import 'package:meta/meta.dart';
import 'package:subiquity_client/subiquity_client.dart';
import 'package:ubuntu_bootstrap/ubuntu_bootstrap.dart';
import 'package:ubuntu_logger/ubuntu_logger.dart';
import 'package:ubuntu_provision/services.dart';

final _log = Logger('keyboard_service');

class SubiquityKeyboardService implements KeyboardService {
const SubiquityKeyboardService(this._subiquity);
SubiquityKeyboardService(
this._subiquity, {
@visibleForTesting GSettings? inputSourceSettings,
}) : _inputSourceSettings = inputSourceSettings ??
createService<GSettings, String>('org.gnome.desktop.input-sources');

final SubiquityClient _subiquity;
final GSettings _inputSourceSettings;

@override
Future<KeyboardSetup> getKeyboard() => _subiquity.getKeyboard();
Expand All @@ -15,7 +27,8 @@ class SubiquityKeyboardService implements KeyboardService {
}

@override
Future<void> setInputSource(KeyboardSetting setting, {String? user}) {
Future<void> setInputSource(KeyboardSetting setting, {String? user}) async {
await _setGsettingsInputSource(setting);
return _subiquity.setInputSource(setting, user: user);
}

Expand All @@ -26,4 +39,22 @@ class SubiquityKeyboardService implements KeyboardService {

@override
bool get canDetectLayout => true;

Future<void> _setGsettingsInputSource(KeyboardSetting setting) async {
try {
final xkbString = setting.variant.isNotEmpty
? '${setting.layout}+${setting.variant}'
: setting.layout;
await _inputSourceSettings.set(
'sources',
DBusArray(
DBusSignature.struct([DBusSignature.string, DBusSignature.string]),
[
DBusStruct([const DBusString('xkb'), DBusString(xkbString)])
]),
);
} on Exception catch (e) {
_log.error('Failed to set input source via gsettings', e);
}
}
}
45 changes: 41 additions & 4 deletions packages/ubuntu_bootstrap/test/services/keyboard_service_test.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import 'package:dbus/dbus.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:gsettings/gsettings.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:subiquity_client/subiquity_client.dart';
import 'package:subiquity_test/subiquity_test.dart';
import 'package:ubuntu_bootstrap/services/keyboard_service.dart';

import '../test_utils.dart';
import 'gnome_accessibility_service_test.mocks.dart';

@GenerateMocks([GSettings])
void main() {
late MockGSettings inputSourceSettings;

setUp(() {
inputSourceSettings = MockGSettings();
when(inputSourceSettings.set(any, any)).thenAnswer((_) async {});
});

test('get keyboard', () async {
final client = MockSubiquityClient();
when(client.getKeyboard()).thenAnswer((_) async => keyboardSetup);

final service = SubiquityKeyboardService(client);
final service = SubiquityKeyboardService(
client,
inputSourceSettings: inputSourceSettings,
);
expect(await service.getKeyboard(), equals(keyboardSetup));

verify(client.getKeyboard()).called(1);
Expand All @@ -21,7 +36,10 @@ void main() {
final client = MockSubiquityClient();
when(client.setKeyboard(keyboardSetup.setting)).thenAnswer((_) async {});

final service = SubiquityKeyboardService(client);
final service = SubiquityKeyboardService(
client,
inputSourceSettings: inputSourceSettings,
);
await service.setKeyboard(keyboardSetup.setting);

verify(client.setKeyboard(keyboardSetup.setting)).called(1);
Expand All @@ -32,19 +50,38 @@ void main() {
when(client.setInputSource(keyboardSetup.setting, user: 'ubuntu'))
.thenAnswer((_) async {});

final service = SubiquityKeyboardService(client);
final service = SubiquityKeyboardService(
client,
inputSourceSettings: inputSourceSettings,
);
await service.setInputSource(keyboardSetup.setting, user: 'ubuntu');

verify(client.setInputSource(keyboardSetup.setting, user: 'ubuntu'))
.called(1);

verify(inputSourceSettings.set(
'sources',
DBusArray(
DBusSignature.struct([DBusSignature.string, DBusSignature.string]),
[
DBusStruct([
const DBusString('xkb'),
const DBusString('us+altgr-intl'),
])
],
),
)).called(1);
});

test('get keyboard step', () async {
final client = MockSubiquityClient();
when(client.getKeyboardStep(any)).thenAnswer(
(_) async => const AnyStep.stepPressKey(keycodes: {}, symbols: []));

final service = SubiquityKeyboardService(client);
final service = SubiquityKeyboardService(
client,
inputSourceSettings: inputSourceSettings,
);
await service.getKeyboardStep('1');

verify(client.getKeyboardStep('1')).called(1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Mocks generated by Mockito 5.4.4 from annotations
// in ubuntu_bootstrap/test/services/keyboard_service_test.dart.
// Do not manually edit this file.

// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i5;

import 'package:dbus/dbus.dart' as _i2;
import 'package:gsettings/src/gsettings.dart' as _i3;
import 'package:mockito/mockito.dart' as _i1;
import 'package:mockito/src/dummies.dart' as _i4;

// ignore_for_file: type=lint
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis
// ignore_for_file: camel_case_types
// ignore_for_file: subtype_of_sealed_class

class _FakeDBusValue_0 extends _i1.SmartFake implements _i2.DBusValue {
_FakeDBusValue_0(
Object parent,
Invocation parentInvocation,
) : super(
parent,
parentInvocation,
);
}

/// A class which mocks [GSettings].
///
/// See the documentation for Mockito's code generation for more information.
class MockGSettings extends _i1.Mock implements _i3.GSettings {
MockGSettings() {
_i1.throwOnMissingStub(this);
}

@override
String get schemaName => (super.noSuchMethod(
Invocation.getter(#schemaName),
returnValue: _i4.dummyValue<String>(
this,
Invocation.getter(#schemaName),
),
) as String);

@override
_i5.Stream<List<String>> get keysChanged => (super.noSuchMethod(
Invocation.getter(#keysChanged),
returnValue: _i5.Stream<List<String>>.empty(),
) as _i5.Stream<List<String>>);

@override
_i5.Future<List<String>> list() => (super.noSuchMethod(
Invocation.method(
#list,
[],
),
returnValue: _i5.Future<List<String>>.value(<String>[]),
) as _i5.Future<List<String>>);

@override
_i5.Future<_i2.DBusValue> get(String? name) => (super.noSuchMethod(
Invocation.method(
#get,
[name],
),
returnValue: _i5.Future<_i2.DBusValue>.value(_FakeDBusValue_0(
this,
Invocation.method(
#get,
[name],
),
)),
) as _i5.Future<_i2.DBusValue>);

@override
_i5.Future<_i2.DBusValue> getDefault(String? name) => (super.noSuchMethod(
Invocation.method(
#getDefault,
[name],
),
returnValue: _i5.Future<_i2.DBusValue>.value(_FakeDBusValue_0(
this,
Invocation.method(
#getDefault,
[name],
),
)),
) as _i5.Future<_i2.DBusValue>);

@override
_i5.Future<bool> isSet(String? name) => (super.noSuchMethod(
Invocation.method(
#isSet,
[name],
),
returnValue: _i5.Future<bool>.value(false),
) as _i5.Future<bool>);

@override
_i5.Future<void> set(
String? name,
_i2.DBusValue? value,
) =>
(super.noSuchMethod(
Invocation.method(
#set,
[
name,
value,
],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);

@override
_i5.Future<void> unset(String? name) => (super.noSuchMethod(
Invocation.method(
#unset,
[name],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);

@override
_i5.Future<void> setAll(Map<String, _i2.DBusValue?>? values) =>
(super.noSuchMethod(
Invocation.method(
#setAll,
[values],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);

@override
_i5.Future<void> close() => (super.noSuchMethod(
Invocation.method(
#close,
[],
),
returnValue: _i5.Future<void>.value(),
returnValueForMissingStub: _i5.Future<void>.value(),
) as _i5.Future<void>);
}

0 comments on commit ce55002

Please sign in to comment.