Skip to content

Commit

Permalink
feat: remove top buttons (#25)
Browse files Browse the repository at this point in the history
* feat: remove top buttons

* feat: add mute button functionality
  • Loading branch information
marwfair authored Aug 2, 2024
1 parent ff34bc2 commit d6c0007
Show file tree
Hide file tree
Showing 11 changed files with 225 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AirplaneEntertainmentSystemScreen extends StatelessWidget {
}

class AirplaneEntertainmentSystemView extends StatefulWidget {
@visibleForTesting
const AirplaneEntertainmentSystemView({super.key});

@override
Expand Down
19 changes: 19 additions & 0 deletions lib/airplane_entertainment_system/widgets/mute_button.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'package:airplane_entertainment_system/music_player/music_player.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class MuteButton extends StatelessWidget {
const MuteButton({super.key});

@override
Widget build(BuildContext context) {
final mute = context.select((MusicPlayerCubit cubit) => cubit.state.mute);

return IconButton(
onPressed: () {
context.read<MusicPlayerCubit>().toggleMute();
},
icon: Icon(mute ? Icons.volume_off : Icons.volume_up),
);
}
}
47 changes: 2 additions & 45 deletions lib/airplane_entertainment_system/widgets/top_button_bar.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:airplane_entertainment_system/airplane_entertainment_system/airplane_entertainment_system.dart';
import 'package:airplane_entertainment_system/generated/assets.gen.dart';
import 'package:airplane_entertainment_system/l10n/l10n.dart';
import 'package:flutter/material.dart';

class TopButtonBar extends StatelessWidget {
Expand All @@ -17,50 +17,7 @@ class TopButtonBar extends StatelessWidget {
children: [
Assets.vgvLogo.image(width: 40, height: 40),
const SizedBox(width: 24),
IconButton(
onPressed: () {},
icon: const Icon(Icons.power_settings_new),
),
Container(
width: 1,
height: 24,
margin: const EdgeInsets.symmetric(horizontal: 8),
color: Colors.white.withOpacity(0.3),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.brightness_7),
),
Container(
width: 1,
height: 24,
margin: const EdgeInsets.symmetric(horizontal: 8),
color: Colors.white.withOpacity(0.3),
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.volume_up),
),
const Spacer(),
ElevatedButton.icon(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue.shade800,
padding: const EdgeInsets.all(16),
textStyle: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 12,
letterSpacing: 1.2,
),
),
icon: const Icon(Icons.support, color: Colors.white),
label: Text(
context.l10n.assistButton,
style: const TextStyle(
color: Colors.white,
),
),
),
const MuteButton(),
],
),
),
Expand Down
1 change: 1 addition & 0 deletions lib/airplane_entertainment_system/widgets/widgets.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export 'mute_button.dart';
export 'system_background.dart';
export 'top_button_bar.dart';
1 change: 0 additions & 1 deletion lib/l10n/arb/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
"songs": "songs",
"welcomeMessage": "Welcome on board",
"welcomeSubtitle": "Lunch will be served in\n10 minutes",
"assistButton": "ASSIST",
"clear": "Clear",
"@clear": {
"description": "The label shown when weather is clear."
Expand Down
8 changes: 8 additions & 0 deletions lib/music_player/cubit/music_player_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class MusicPlayerCubit extends Cubit<MusicPlayerState> {
_player.onPlayerStateChanged.listen(_onIsPlayingChanged);
_progressSubscription =
_player.onPositionChanged.listen(_onProgressChanged);

_player.setVolume(1);
}

final MusicRepository _musicRepository;
Expand Down Expand Up @@ -155,6 +157,12 @@ class MusicPlayerCubit extends Cubit<MusicPlayerState> {
}
}

void toggleMute() {
final mute = !state.mute;
_player.setVolume(mute ? 0 : 1);
emit(state.copyWith(mute: mute));
}

@override
Future<void> close() {
_isPlayingSubscription.cancel();
Expand Down
5 changes: 5 additions & 0 deletions lib/music_player/cubit/music_player_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class MusicPlayerState extends Equatable {
this.isPlaying = false,
this.isLoop = false,
this.shuffleIndexes = const [],
this.mute = false,
});

final List<MusicTrack> tracks;
Expand All @@ -18,6 +19,7 @@ class MusicPlayerState extends Equatable {
final bool isPlaying;
final bool isLoop;
final List<int> shuffleIndexes;
final bool mute;

bool get isShuffle => shuffleIndexes.isNotEmpty;

Expand All @@ -34,6 +36,7 @@ class MusicPlayerState extends Equatable {
progress,
isLoop,
shuffleIndexes,
mute,
];

MusicPlayerState copyWith({
Expand All @@ -44,6 +47,7 @@ class MusicPlayerState extends Equatable {
bool? isPlaying,
bool? isLoop,
List<int>? shuffleIndexes,
bool? mute,
}) {
return MusicPlayerState(
tracks: tracks ?? this.tracks,
Expand All @@ -53,6 +57,7 @@ class MusicPlayerState extends Equatable {
progress: progress ?? this.progress,
isLoop: isLoop ?? this.isLoop,
shuffleIndexes: shuffleIndexes ?? this.shuffleIndexes,
mute: mute ?? this.mute,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import 'package:aes_ui/aes_ui.dart';
import 'package:airplane_entertainment_system/airplane_entertainment_system/airplane_entertainment_system.dart';
import 'package:airplane_entertainment_system/music_player/music_player.dart';
import 'package:airplane_entertainment_system/overview/overview.dart';
import 'package:airplane_entertainment_system/weather/weather.dart';
import 'package:audioplayers/audioplayers.dart';
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:music_repository/music_repository.dart';
Expand All @@ -13,6 +16,14 @@ import '../../helpers/helpers.dart';

class _MockAudioCache extends Mock implements AudioCache {}

class _MockAudioPlayer extends Mock implements AudioPlayer {}

class _MockWeatherBloc extends MockBloc<WeatherEvent, WeatherState>
implements WeatherBloc {}

class _MockMusicPlayerCubit extends MockCubit<MusicPlayerState>
implements MusicPlayerCubit {}

void main() {
group('$AirplaneEntertainmentSystemScreen', () {
late WeatherRepository weatherRepository;
Expand All @@ -27,7 +38,7 @@ void main() {
musicRepository = MockMusicRepository();
when(musicRepository.getTracks).thenReturn(const []);

audioPlayer = MockAudioPlayer();
audioPlayer = _MockAudioPlayer();
when(() => audioPlayer.onPositionChanged)
.thenAnswer((_) => const Stream.empty());
when(() => audioPlayer.onPlayerStateChanged)
Expand All @@ -36,67 +47,75 @@ void main() {

final audioCache = _MockAudioCache();
when(() => audioPlayer.audioCache).thenReturn(audioCache);
when(() => audioPlayer.setVolume(any())).thenAnswer((_) async {});
});

testWidgets('shows $AesNavigationRail on large screens', (tester) async {
await tester.binding.setSurfaceSize(const Size(1600, 1200));
testWidgets('finds one AirplaneEntertainmentSystemView Widget',
(tester) async {
await tester.pumpApp(
const AirplaneEntertainmentSystemScreen(),
layout: AesLayoutData.large,
layout: AesLayoutData.small,
musicRepository: musicRepository,
weatherRepository: weatherRepository,
audioPlayer: audioPlayer,
);

expect(find.byType(AirplaneEntertainmentSystemView), findsOneWidget);
});
});

group('$AirplaneEntertainmentSystemView', () {
testWidgets('shows $AesNavigationRail on large screens', (tester) async {
await tester.binding.setSurfaceSize(const Size(1600, 1200));
await tester.pumpSubject(
const AirplaneEntertainmentSystemView(),
AesLayoutData.large,
);

expect(find.byType(AesNavigationRail), findsOneWidget);
});

testWidgets('shows $AesBottomNavigationBar on small screens',
(tester) async {
await tester.pumpApp(
const AirplaneEntertainmentSystemScreen(),
layout: AesLayoutData.small,
weatherRepository: weatherRepository,
await tester.pumpSubject(
const AirplaneEntertainmentSystemView(),
AesLayoutData.small,
);

expect(find.byType(AesBottomNavigationBar), findsOneWidget);
});

testWidgets('shows TopButtonBar', (tester) async {
await tester.pumpApp(
const AirplaneEntertainmentSystemScreen(),
layout: AesLayoutData.small,
weatherRepository: weatherRepository,
await tester.pumpSubject(
const AirplaneEntertainmentSystemView(),
AesLayoutData.small,
);

expect(find.byType(TopButtonBar), findsOneWidget);
});

testWidgets('contains background', (tester) async {
await tester.pumpApp(
const AirplaneEntertainmentSystemScreen(),
layout: AesLayoutData.small,
weatherRepository: weatherRepository,
await tester.pumpSubject(
const AirplaneEntertainmentSystemView(),
AesLayoutData.small,
);

expect(find.byType(SystemBackground), findsOneWidget);
});

testWidgets('shows OverviewPage initially', (tester) async {
await tester.pumpApp(
const AirplaneEntertainmentSystemScreen(),
layout: AesLayoutData.small,
weatherRepository: weatherRepository,
await tester.pumpSubject(
const AirplaneEntertainmentSystemView(),
AesLayoutData.small,
);

expect(find.byType(OverviewPage), findsOneWidget);
});

testWidgets('shows MusicPlayerPage when icon is selected', (tester) async {
await tester.pumpApp(
const AirplaneEntertainmentSystemScreen(),
layout: AesLayoutData.small,
weatherRepository: weatherRepository,
musicRepository: musicRepository,
audioPlayer: audioPlayer,
await tester.pumpSubject(
const AirplaneEntertainmentSystemView(),
AesLayoutData.small,
);

await tester.tap(find.byIcon(Icons.music_note));
Expand All @@ -110,12 +129,9 @@ void main() {
testWidgets(
'shows $OverviewPage when icon is '
'selected for $layout layout', (tester) async {
await tester.pumpApp(
const AirplaneEntertainmentSystemScreen(),
layout: layout,
weatherRepository: weatherRepository,
musicRepository: musicRepository,
audioPlayer: audioPlayer,
await tester.pumpSubject(
const AirplaneEntertainmentSystemView(),
layout,
);

await tester.tap(find.byIcon(Icons.music_note));
Expand All @@ -129,3 +145,24 @@ void main() {
}
});
}

extension on WidgetTester {
Future<void> pumpSubject(Widget widget, AesLayoutData layout) {
final MusicPlayerCubit musicPlayerCubit = _MockMusicPlayerCubit();
when(() => musicPlayerCubit.state).thenReturn(const MusicPlayerState());

final WeatherBloc weatherBloc = _MockWeatherBloc();
when(() => weatherBloc.state).thenReturn(const WeatherState());

return pumpApp(
MultiBlocProvider(
providers: [
BlocProvider.value(value: musicPlayerCubit),
BlocProvider.value(value: weatherBloc),
],
child: widget,
),
layout: layout,
);
}
}
Loading

0 comments on commit d6c0007

Please sign in to comment.