Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Riverpod #111

Open
wants to merge 48 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
8236cc2
Start implementing riverpod
Barabas5532 Feb 3, 2024
be13273
clean up
Barabas5532 Feb 3, 2024
f303381
Connect midi learn service
Barabas5532 Feb 3, 2024
2875093
refactor connection status
Barabas5532 Feb 3, 2024
13c09fe
Convert API websocket
Barabas5532 Feb 3, 2024
10b58c0
convert audio events
Barabas5532 Feb 3, 2024
f2ede33
refactor midi mapping transport
Barabas5532 Feb 3, 2024
5eec4b6
Refactor midi mapping service
Barabas5532 Feb 3, 2024
50e7107
Refactor parameter transport
Barabas5532 Feb 3, 2024
d8dff74
Refactor parameter service
Barabas5532 Feb 3, 2024
4627d0f
Remove some provider
Barabas5532 Feb 3, 2024
893fa11
Remove more provider
Barabas5532 Feb 3, 2024
8cf855b
refactor presets transport
Barabas5532 Feb 3, 2024
cfe95cd
Refactor presets client
Barabas5532 Feb 3, 2024
f818d81
refactor presets repository
Barabas5532 Feb 3, 2024
279b103
refactor selected preset
Barabas5532 Feb 3, 2024
5402055
WIP refactor presets service
Barabas5532 Feb 3, 2024
ab60c57
Refactor to fix parameter error
Barabas5532 Feb 3, 2024
21aba07
remove more providers
Barabas5532 Feb 3, 2024
45016b8
refactor midi learn service
Barabas5532 Feb 3, 2024
71a25fe
Remove ApiWebsocket provider
Barabas5532 Feb 3, 2024
60b536d
refactory midi mapping service
Barabas5532 Feb 3, 2024
c1ca52c
remove provider for midi learn
Barabas5532 Feb 3, 2024
81ea5d0
remove more provider
Barabas5532 Feb 3, 2024
d31e74e
remove provider
Barabas5532 Feb 3, 2024
532024d
Fix tests
Barabas5532 Mar 14, 2024
d263668
refactor preset stream
Barabas5532 Mar 14, 2024
b3699b3
refactor selected preset provider
Barabas5532 Mar 14, 2024
d71421a
Change presets service to generated provider
Barabas5532 Mar 14, 2024
1275fb9
Convert everything to code generation, fix lints
Barabas5532 Mar 15, 2024
db8c1fd
Fix provider read across async causing issues
Barabas5532 Mar 15, 2024
0cfa3fb
Convert all read to watch where appropriate
Barabas5532 Mar 20, 2024
6a9b35d
Fix UI issues in loading state
Barabas5532 Mar 20, 2024
996fd23
Change more reads to watch
Barabas5532 Mar 20, 2024
11ef812
WIP
Barabas5532 Mar 24, 2024
c21ee5b
Reset all client state when disconnected
Barabas5532 Mar 24, 2024
6235263
WIP fix tests
Barabas5532 Mar 24, 2024
893eb26
fix loading midi mappings
Barabas5532 Mar 25, 2024
eaf9122
fix midi learn duplicate handling
Barabas5532 Mar 25, 2024
d26a49d
fix tests
Barabas5532 Mar 25, 2024
90412a3
fix lint
Barabas5532 Mar 25, 2024
3783290
fix license headers
Barabas5532 Mar 25, 2024
a8c4668
Merge remote-tracking branch 'origin/master' into riverpod
Barabas5532 Jul 23, 2024
d8f6f33
fix preset loading when no presets have been created
Barabas5532 Jul 23, 2024
7cb4083
fix some UI not reverting to loading state on disconnect
Barabas5532 Jul 23, 2024
573bcac
clean up logs
Barabas5532 Jul 23, 2024
596ac26
WIP set up API test
Barabas5532 Jul 23, 2024
93369bc
fix API test
Barabas5532 Jul 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions frontend/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ analyzer:
# We explicitly enabled even conflicting rules and are fixing the conflict
# in this file
included_file_warning: ignore
plugins:
- custom_lint
linter:
rules:
# too verbose
Expand Down
24 changes: 16 additions & 8 deletions frontend/integration_test/simple_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
library;

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:logging/logging.dart';
import 'package:shrapnel/api/api_websocket.dart';
import 'package:shrapnel/main.dart';
import 'package:shrapnel/midi_mapping/model/models.dart';

Expand Down Expand Up @@ -113,9 +115,12 @@ void main() {

// mDNS seems to be slow, use the IP address directly for faster testing.
await tester.pumpWidget(
App(
normalHost: dutIpAddress,
provisioningHost: '192.168.4.1',
ProviderScope(
overrides: [
normalHostProvider.overrideWithValue(dutIpAddress),
provisioningHostProvider.overrideWithValue('192.168.4.1'),
],
child: App(),
),
);

Expand Down Expand Up @@ -201,17 +206,20 @@ void main() {
testWidgets('simple test', (tester) async {
// mDNS seems to be slow, use the IP address directly for faster testing.
await tester.pumpWidget(
App(
normalHost: dutIpAddress,
provisioningHost: '192.168.4.1',
ProviderScope(
overrides: [
normalHostProvider.overrideWithValue(dutIpAddress),
provisioningHostProvider.overrideWithValue('192.168.4.1'),
],
child: App(),
),
);

// wait until connected
// poll connection status widget until ready with timeout
final homePage = HomePageObject(tester);
await homePage.waitUntilConnected();

await homePage.waitUntilPresetsReady();

await homePage.createPreset('Preset 1');

final midiMappingPage = await homePage.openMidiMapping();
Expand Down
58 changes: 6 additions & 52 deletions frontend/lib/amplifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,13 @@
*/

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';

import 'knob_with_label.dart';
import 'parameter.dart';

abstract class AmplifierModel {
String get name;
List<AudioParameterDoubleModel> get parameters;

List<String> get parameters;
}

class Amplifier extends StatelessWidget {
Expand All @@ -47,11 +45,10 @@ class Amplifier extends StatelessWidget {

for (var i = 0; i < parameters.length; i++) {
knobs.add(
parameters[i].provider(
child: KnobWithLabel(
isEnabled: full,
knobSize: scaleFactor * 25,
),
KnobWithLabel(
isEnabled: full,
knobSize: scaleFactor * 25,
parameterId: parameters[i],
),
);
if (i < parameters.length - 1) {
Expand Down Expand Up @@ -80,46 +77,3 @@ class Amplifier extends StatelessWidget {
);
}
}

extension ProviderEx<T> on ValueStream<T> {
Widget provider({
Key? key,
ErrorBuilder<T>? catchError,
UpdateShouldNotify<T>? updateShouldNotify,
bool? lazy,
TransitionBuilder? builder,
Widget? child,
}) {
return StreamProvider<T>.value(
key: key,
value: this,
initialData: value,
updateShouldNotify: updateShouldNotify,
lazy: lazy,
builder: builder,
child: child,
);
}
}

extension ParameterProviderEx on AudioParameterDoubleModel {
Widget provider({
Key? key,
ErrorBuilder<double>? catchError,
UpdateShouldNotify<double>? updateShouldNotify,
bool? lazy,
TransitionBuilder? builder,
Widget? child,
}) {
return Provider.value(
value: this,
child: value.provider(
key: key,
updateShouldNotify: updateShouldNotify,
lazy: lazy,
builder: builder,
child: child,
),
);
}
}
47 changes: 36 additions & 11 deletions frontend/lib/api/api_websocket.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import 'dart:async';
import 'package:async/async.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:logging/logging.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:rxdart/rxdart.dart';

import '../audio_events.dart';
Expand All @@ -37,8 +38,24 @@ import 'proto_extension.dart';

part 'api_websocket.freezed.dart';

part 'api_websocket.g.dart';

final _log = Logger('api_websocket');

@Riverpod(keepAlive: true)
String normalHost(NormalHostRef ref) => 'guitar-dsp.local';

@Riverpod(keepAlive: true)
String provisioningHost(ProvisioningHostRef ref) => 'guitar-dsp.local';

@visibleForTesting
final kShrapnelUri = Uri(
scheme: 'http',
host: 'guitar-dsp.local',
port: 8080,
path: '/websocket',
);

@freezed
sealed class ApiMessage with _$ApiMessage {
const factory ApiMessage.audioEvent({required AudioEventMessage message}) =
Expand All @@ -63,14 +80,28 @@ sealed class ApiMessage with _$ApiMessage {
}) = ApiMessageSelectedPreset;
}

class ApiWebsocket
implements ReconnectingMessageTransport<ApiMessage, ApiMessage> {
@riverpod
Uri shrapnelUri(ShrapnelUriRef ref) {
return kShrapnelUri.replace(host: ref.watch(normalHostProvider));
}

@riverpod
ApiWebsocket? apiWebsocket(ApiWebsocketRef ref) {
final websocket =
ref.watch(robustWebsocketProvider(ref.watch(shrapnelUriProvider)));
if (websocket.isAlive) {
return ApiWebsocket(websocket: websocket);
}

return null;
}

class ApiWebsocket implements MessageTransport<ApiMessage, ApiMessage> {
ApiWebsocket({
required ReconnectingMessageTransport<WebSocketData, WebSocketData>
websocket,
required MessageTransport<WebSocketData, WebSocketData> websocket,
}) : _websocket = websocket;

final ReconnectingMessageTransport<WebSocketData, WebSocketData> _websocket;
final MessageTransport<WebSocketData, WebSocketData> _websocket;

@override
late final Stream<ApiMessage> stream = _websocket.stream
Expand All @@ -83,12 +114,6 @@ class ApiWebsocket
(event) => 'received: $event',
);

@override
late final Stream<void> connectionStream = _websocket.connectionStream;

@override
bool get isAlive => _websocket.isAlive;

@override
late final StreamSink<ApiMessage> sink =
StreamSinkTransformer<ApiMessage, WebSocketData>.fromHandlers(
Expand Down
1 change: 1 addition & 0 deletions frontend/lib/api/generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ protoc --dart_out="$proto_dir/generated" \
presets.proto \
selected_preset.proto \
shrapnel.proto
dart format "$proto_dir/generated"
19 changes: 19 additions & 0 deletions frontend/lib/audio_events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@
*/

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:logging/logging.dart';
import 'package:pausable_timer/pausable_timer.dart';
import 'package:rxdart/rxdart.dart';

import 'api/api_websocket.dart';

part 'audio_events.freezed.dart';

Expand All @@ -33,6 +37,21 @@ sealed class AudioEventMessage with _$AudioEventMessage {
factory AudioEventMessage.outputClipped() = AudioEventMessageOutputClipped;
}

final audioClippingServiceProvider = AutoDisposeChangeNotifierProvider(
(ref) {
final websocket = ref.watch(apiWebsocketProvider);
if (websocket != null) {
return AudioClippingService(
stream: websocket.stream
.whereType<ApiMessageAudioEvent>()
.map((event) => event.message),
);
}

return null;
},
);

class AudioClippingService extends ChangeNotifier {
AudioClippingService({required Stream<AudioEventMessage> stream}) {
_outputClippingTimer = PausableTimer(
Expand Down
39 changes: 9 additions & 30 deletions frontend/lib/chorus.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,47 +18,26 @@
*/

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'parameter.dart';
import 'stompbox.dart';

class ChorusModel extends StompboxModel {
ChorusModel({required ParameterService parameterService})
ChorusModel()
: parameters = [
AudioParameterDoubleModel(
groupName: _name,
name: 'DEPTH',
id: 'chorusDepth',
parameterService: parameterService,
),
AudioParameterDoubleModel(
groupName: _name,
name: 'MIX',
id: 'chorusMix',
parameterService: parameterService,
),
AudioParameterDoubleModel(
groupName: _name,
name: 'RATE',
id: 'chorusRate',
parameterService: parameterService,
),
'chorusDepth',
'chorusMix',
'chorusRate',
],
bypass = AudioParameterDoubleModel(
groupName: _name,
name: 'Bypass',
id: 'chorusBypass',
parameterService: parameterService,
);
bypass = 'chorusBypass';

static const _name = 'Chorus';

@override
String get name => _name;
@override
final List<AudioParameterDoubleModel> parameters;
final List<String> parameters;
@override
final AudioParameterDoubleModel bypass;
final String bypass;
}

class Chorus extends StatelessWidget {
Expand All @@ -74,7 +53,7 @@ class Chorus extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Stompbox(
model: context.read<ChorusModel>(),
model: ChorusModel(),
onCardTap: onTap,
full: full,
primarySwatch: Colors.blue,
Expand Down
3 changes: 0 additions & 3 deletions frontend/lib/core/message_transport.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,4 @@ abstract class ReconnectingMessageTransport<T1, T2>
extends MessageTransport<T1, T2> {
/// Returns true if the connection is alive at the moment
bool get isAlive;

/// A null is emitted every time a connection is successfully created
Stream<void> get connectionStream;
}
Loading
Loading