Tugas PPB 13 Membuat Aplikasi Musik
TUGAS PPB 13
Membuat Aplikasi Musik
Nama: Fayyadh Hafizh
NRP : 5025201164
Kelas: PPB I
Link Github: Tugas 13
Halo temen-temen semuanya! Pada kesempatan kali ini, kita akan mencoba membuat sebuah aplikasi musik menggunakan framework Flutter. Aplikasi ini nantinya dapat memutar musik, melihat daftar lagu, melihat artist dan lagu-lagunya, dan masih banyak lagi. Aplikasi ini dibuat dengan mengikuti panduan dari Codelabs dengan melewati beberapa step. Untuk beberapa kode yang umum dan hasil implementasinya dapat dilihat dibawah ini.
- Kode Implementasi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2022 The Flutter Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
import 'package:desktop_window/desktop_window.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:universal_platform/universal_platform.dart'; | |
import 'src/shared/app.dart'; | |
Future setDesktopWindow() async { | |
await DesktopWindow.setMinWindowSize(const Size(400, 400)); | |
await DesktopWindow.setWindowSize(const Size(1300, 900)); | |
} | |
void main() { | |
WidgetsFlutterBinding.ensureInitialized(); | |
if (UniversalPlatform.isDesktop) { | |
setDesktopWindow(); | |
} | |
runApp(const MyApp()); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2022 The Flutter Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
import 'package:dynamic_color/dynamic_color.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'playback/bloc/bloc.dart'; | |
import 'providers/theme.dart'; | |
import 'router.dart'; | |
import 'views/views.dart'; | |
class MyApp extends StatefulWidget { | |
const MyApp({super.key}); | |
@override | |
State<MyApp> createState() => _MyAppState(); | |
} | |
class _MyAppState extends State<MyApp> { | |
final settings = ValueNotifier(ThemeSettings( | |
sourceColor: Color(0xff00cbe6), // Replace this color | |
themeMode: ThemeMode.system, | |
)); | |
@override | |
Widget build(BuildContext context) { | |
return BlocProvider<PlaybackBloc>( | |
create: (context) => PlaybackBloc(), | |
child: DynamicColorBuilder( | |
builder: (lightDynamic, darkDynamic) => ThemeProvider( | |
lightDynamic: lightDynamic, | |
darkDynamic: darkDynamic, | |
settings: settings, | |
child: NotificationListener<ThemeSettingChange>( | |
onNotification: (notification) { | |
settings.value = notification.settings; | |
return true; | |
}, | |
child: ValueListenableBuilder<ThemeSettings>( | |
valueListenable: settings, | |
builder: (context, value, _) { | |
final theme = ThemeProvider.of(context); | |
return MaterialApp.router( | |
debugShowCheckedModeBanner: false, | |
title: 'Flutter Demo', | |
theme: theme.light(settings.value.sourceColor), | |
darkTheme: theme.dark(settings.value.sourceColor), | |
themeMode: theme.themeMode(), | |
routeInformationParser: appRouter.routeInformationParser, | |
routeInformationProvider: | |
appRouter.routeInformationProvider, | |
routerDelegate: appRouter.routerDelegate, | |
builder: (context, child) { | |
return PlayPauseListener(child: child!); | |
}, | |
); | |
}, | |
), | |
)), | |
), | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2022 The Flutter Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
import 'package:flutter/material.dart'; | |
import 'package:google_fonts/google_fonts.dart'; | |
// Add Google Fonts Package import | |
extension TypographyUtils on BuildContext { | |
ThemeData get theme => Theme.of(this); | |
TextTheme get textTheme => | |
GoogleFonts.montserratTextTheme(theme.textTheme); // Modify this line | |
ColorScheme get colors => theme.colorScheme; | |
TextStyle? get displayLarge => textTheme.displayLarge?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get displayMedium => textTheme.displayMedium?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get displaySmall => textTheme.displaySmall?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get headlineLarge => textTheme.headlineLarge?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get headlineMedium => textTheme.headlineMedium?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get headlineSmall => textTheme.headlineSmall?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get titleLarge => textTheme.titleLarge?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get titleMedium => textTheme.titleMedium?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get titleSmall => textTheme.titleSmall?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get labelLarge => textTheme.labelLarge?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get labelMedium => textTheme.labelMedium?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get labelSmall => textTheme.labelSmall?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get bodyLarge => textTheme.bodyLarge?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get bodyMedium => textTheme.bodyMedium?.copyWith( | |
color: colors.onSurface, | |
); | |
TextStyle? get bodySmall => textTheme.bodySmall?.copyWith( | |
color: colors.onSurface, | |
); | |
} | |
extension BreakpointUtils on BoxConstraints { | |
bool get isTablet => maxWidth > 730; | |
bool get isDesktop => maxWidth > 1200; | |
bool get isMobile => !isTablet && !isDesktop; | |
} | |
extension DurationString on String { | |
/// Assumes a string (roughly) of the format '\d{1,2}:\d{2}' | |
Duration toDuration() => switch (split(':')) { | |
[var minutes, var seconds] => Duration( | |
minutes: int.parse(minutes.trim()), | |
seconds: int.parse(seconds.trim()), | |
), | |
[var hours, var minutes, var seconds] => Duration( | |
hours: int.parse(hours.trim()), | |
minutes: int.parse(minutes.trim()), | |
seconds: int.parse(seconds.trim()), | |
), | |
_ => throw Exception('Invalid duration string: $this'), | |
}; | |
} | |
extension HumanizedDuration on Duration { | |
String toHumanizedString() { | |
final seconds = '${inSeconds % 60}'.padLeft(2, '0'); | |
String minutes = '${inMinutes % 60}'; | |
if (inHours > 0 || inMinutes == 0) { | |
minutes = minutes.padLeft(2, '0'); | |
} | |
String value = '$minutes:$seconds'; | |
if (inHours > 0) { | |
value = '$inHours:$minutes:$seconds'; | |
} | |
return value; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2022 The Flutter Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style license that can be | |
// found in the LICENSE file. | |
import 'package:flutter/material.dart'; | |
import 'package:go_router/go_router.dart'; | |
import '../features/artists/artists.dart'; | |
import '../features/home/home.dart'; | |
import '../features/playlists/playlists.dart'; | |
import '../features/playlists/view/view.dart'; | |
import 'providers/artists.dart'; | |
import 'providers/playlists.dart'; | |
import 'views/views.dart'; | |
const _pageKey = ValueKey('_pageKey'); | |
const _scaffoldKey = ValueKey('_scaffoldKey'); | |
final artistsProvider = ArtistsProvider(); | |
final playlistsProvider = PlaylistsProvider(); | |
const List<NavigationDestination> destinations = [ | |
NavigationDestination( | |
label: 'Home', | |
icon: Icon(Icons.home), // Modify this line | |
route: '/', | |
), | |
NavigationDestination( | |
label: 'Playlists', | |
icon: Icon(Icons.playlist_add_check), // Modify this line | |
route: '/playlists', | |
), | |
NavigationDestination( | |
label: 'Artists', | |
icon: Icon(Icons.people), // Modify this line | |
route: '/artists', | |
), | |
]; | |
class NavigationDestination { | |
const NavigationDestination({ | |
required this.route, | |
required this.label, | |
required this.icon, | |
this.child, | |
}); | |
final String route; | |
final String label; | |
final Icon icon; | |
final Widget? child; | |
} | |
final appRouter = GoRouter( | |
routes: [ | |
// HomeScreen | |
GoRoute( | |
path: '/', | |
pageBuilder: (context, state) => const MaterialPage<void>( | |
key: _pageKey, | |
child: RootLayout( | |
key: _scaffoldKey, | |
currentIndex: 0, | |
child: HomeScreen(), | |
), | |
), | |
), | |
// PlaylistHomeScreen | |
GoRoute( | |
path: '/playlists', | |
pageBuilder: (context, state) => const MaterialPage<void>( | |
key: _pageKey, | |
child: RootLayout( | |
key: _scaffoldKey, | |
currentIndex: 1, | |
child: PlaylistHomeScreen(), | |
), | |
), | |
routes: [ | |
GoRoute( | |
path: ':pid', | |
pageBuilder: (context, state) => MaterialPage<void>( | |
key: state.pageKey, | |
child: RootLayout( | |
key: _scaffoldKey, | |
currentIndex: 1, | |
child: PlaylistScreen( | |
playlist: playlistsProvider | |
.getPlaylist(state.pathParameters['pid']!)!, | |
), | |
), | |
), | |
), | |
], | |
), | |
// ArtistHomeScreen | |
GoRoute( | |
path: '/artists', | |
pageBuilder: (context, state) => const MaterialPage<void>( | |
key: _pageKey, | |
child: RootLayout( | |
key: _scaffoldKey, | |
currentIndex: 2, | |
child: ArtistsScreen(), | |
), | |
), | |
routes: [ | |
GoRoute( | |
path: ':aid', | |
pageBuilder: (context, state) => MaterialPage<void>( | |
key: state.pageKey, | |
child: RootLayout( | |
key: _scaffoldKey, | |
currentIndex: 2, | |
child: ArtistScreen( | |
artist: | |
artistsProvider.getArtist(state.pathParameters['aid']!)!, | |
), | |
), | |
), | |
// builder: (context, state) => ArtistScreen( | |
// id: state.params['aid']!, | |
// ), | |
), | |
], | |
), | |
for (final route in destinations.skip(3)) | |
GoRoute( | |
path: route.route, | |
pageBuilder: (context, state) => MaterialPage<void>( | |
key: _pageKey, | |
child: RootLayout( | |
key: _scaffoldKey, | |
currentIndex: destinations.indexOf(route), | |
child: const SizedBox(), | |
), | |
), | |
), | |
], | |
); |
- Hasil Implementasi
Komentar
Posting Komentar