Membuat Aplikasi Flutter Music

 

PPB I - Tugas 13


Membuat Aplikasi Flutter Music


    Nama :Michael Ariel Manihuruk
    NRP : 5025201158
    Kelas : PPB-I
    Link Github : Tugas 13

    Hai semuanya ! Pada kesempatan ini, kita akan mencoba membuat aplikasi pemutar musik yang memungkinkan penggemar untuk terus mengikuti kabar terbaru dari artis favorit mereka. Aplikasi ini akan menampilkan foto dan deskripsi artis, daftar album lagu, serta komentar dari penggemar. Pengguna dapat melihat profil artis, mendengarkan lagu-lagu terbaru, dan membaca atau memberikan komentar. Berikut adalah beberapa kode program penting untuk pengembangan aplikasi ini.

    Kode implementasi yang digunakan untuk menampilkan halaman home.

// 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 '../../../shared/classes/classes.dart';
import '../../../shared/providers/providers.dart';
import '../../../shared/views/views.dart';
class PlaylistHomeScreen extends StatelessWidget {
const PlaylistHomeScreen({super.key});
@override
Widget build(BuildContext context) {
PlaylistsProvider playlistProvider = PlaylistsProvider();
List<Playlist> playlists = playlistProvider.playlists;
return LayoutBuilder(
builder: (context, constraints) {
return Scaffold(
primary: false,
appBar: AppBar(
title: const Text('PLAYLISTS'),
toolbarHeight: kToolbarHeight * 2,
),
body: Column(
children: [
Expanded(
child: GridView.builder(
padding: const EdgeInsets.all(15),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: (constraints.maxWidth ~/ 175).toInt(),
childAspectRatio: 0.70,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
),
itemCount: playlists.length,
itemBuilder: (context, index) {
final playlist = playlists[index];
return GestureDetector(
child: ImageTile(
image: playlist.cover.image,
title: playlist.title,
subtitle: playlist.description,
),
onTap: () =>
GoRouter.of(context).go('/playlists/${playlist.id}'),
);
},
),
),
],
),
);
},
);
}
}
    Kode implementasi yang digunakan untuk menampilkan halaman playlist.

// 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 'dart:math';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../../../shared/classes/classes.dart';
import '../../../shared/extensions.dart';
import '../../../shared/views/adaptive_image_card.dart';
import '../../../shared/views/views.dart';
import 'playlist_songs.dart';
class PlaylistScreen extends StatelessWidget {
const PlaylistScreen({required this.playlist, super.key});
final Playlist playlist;
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
final colors = Theme.of(context).colorScheme;
final double headerHeight = constraints.isMobile
? max(constraints.biggest.height * 0.5, 450)
: max(constraints.biggest.height * 0.25, 250);
if (constraints.isMobile) {
return Scaffold(
appBar: AppBar(
leading: BackButton(
onPressed: () => GoRouter.of(context).go('/playlists'),
),
title: Text(playlist.title),
actions: [
IconButton(
icon: const Icon(Icons.play_circle_fill),
onPressed: () {},
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.shuffle),
),
],
),
body: ArticleContent(
child: PlaylistSongs(
playlist: playlist,
constraints: constraints,
),
),
);
}
return Scaffold(
body: CustomScrollView(
slivers: [
SliverAppBar(
leading: BackButton(
onPressed: () => GoRouter.of(context).go('/playlists'),
),
expandedHeight: headerHeight,
pinned: false,
flexibleSpace: FlexibleSpaceBar(
background: AdaptiveImageCard(
axis: constraints.isMobile ? Axis.vertical : Axis.horizontal,
constraints:
constraints.copyWith(maxHeight: headerHeight).normalize(),
image: playlist.cover.image,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
'PLAYLIST',
style: context.titleSmall!
.copyWith(color: colors.onSurface),
),
Text(
playlist.title,
style: context.displaySmall!
.copyWith(color: colors.onSurface),
),
Text(
playlist.description,
style: context.bodyLarge!.copyWith(
color: colors.onSurface.withOpacity(0.8),
),
),
const SizedBox(height: 8),
Row(
children: [
IconButton(
icon: Icon(
Icons.play_circle_fill,
color: colors.tertiary,
),
onPressed: () {},
),
TextButton.icon(
onPressed: () {},
icon: Icon(
Icons.shuffle,
color: colors.tertiary,
),
label: Text(
'Shuffle',
style: context.bodySmall!.copyWith(
color: colors.tertiary,
),
),
),
],
),
],
),
),
),
),
SliverToBoxAdapter(
child: ArticleContent(
child: PlaylistSongs(
playlist: playlist,
constraints: constraints,
),
),
),
],
),
);
});
}
}
    Kode implementasi yang digunakan untuk menampilkan halaman artist.

// 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:flutter_bloc/flutter_bloc.dart';
import '../../../shared/classes/classes.dart';
import '../../../shared/extensions.dart';
import '../../../shared/playback/bloc/bloc.dart';
import '../../../shared/views/image_clipper.dart';
import '../../../shared/views/views.dart';
class PlaylistSongs extends StatelessWidget {
const PlaylistSongs(
{super.key, required this.playlist, required this.constraints});
final Playlist playlist;
final BoxConstraints constraints;
@override
Widget build(BuildContext context) {
return AdaptiveTable<Song>(
items: playlist.songs,
breakpoint: 450,
columns: const [
DataColumn(
label: Padding(
padding: EdgeInsets.only(left: 20),
child: Text('#'),
),
),
DataColumn(
label: Text('Title'),
),
DataColumn(
label: Padding(
padding: EdgeInsets.only(right: 10),
child: Text('Length'),
),
),
],
rowBuilder: (context, index) => DataRow.byIndex(
index: index,
cells: [
DataCell(
// Add HoverableSongPlayButton
HoverableSongPlayButton(
// Add this line
hoverMode: HoverMode.overlay, // Add this line
song: playlist.songs[index], // Add this line
child: Center(
// Modify this line
child: Text(
(index + 1).toString(),
textAlign: TextAlign.center,
),
),
), // Add this line
),
DataCell(
Row(children: [
Padding(
padding: const EdgeInsets.all(2),
child: ClippedImage(playlist.songs[index].image.image),
),
const SizedBox(width: 10),
Expanded(child: Text(playlist.songs[index].title)),
]),
),
DataCell(
Text(playlist.songs[index].length.toHumanizedString()),
),
],
),
itemBuilder: (song, index) {
return ListTile(
onTap: () => BlocProvider.of<PlaybackBloc>(context).add(
PlaybackEvent.changeSong(song),
),
leading: ClippedImage(song.image.image),
title: Text(song.title),
subtitle: Text(song.length.toHumanizedString()),
);
},
);
}
}
    Selain itu, pada implementasi kali ini, aplikasi memiliki dua mode yaitu mode dark dan light. Adapun implementasinya dapat kita lihat melalui kode berikut.

// 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 'dart:math';
import 'package:flutter/material.dart';
import 'package:material_color_utilities/material_color_utilities.dart';
class NoAnimationPageTransitionsBuilder extends PageTransitionsBuilder {
const NoAnimationPageTransitionsBuilder();
@override
Widget buildTransitions<T>(
PageRoute<T> route,
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
) {
return child;
}
}
class ThemeSettingChange extends Notification {
ThemeSettingChange({required this.settings});
final ThemeSettings settings;
}
class ThemeProvider extends InheritedWidget {
const ThemeProvider(
{super.key,
required this.settings,
required this.lightDynamic,
required this.darkDynamic,
required super.child});
final ValueNotifier<ThemeSettings> settings;
final ColorScheme? lightDynamic;
final ColorScheme? darkDynamic;
final pageTransitionsTheme = const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
TargetPlatform.linux: NoAnimationPageTransitionsBuilder(),
TargetPlatform.macOS: NoAnimationPageTransitionsBuilder(),
TargetPlatform.windows: NoAnimationPageTransitionsBuilder(),
},
);
Color custom(CustomColor custom) {
if (custom.blend) {
return blend(custom.color);
} else {
return custom.color;
}
}
Color blend(Color targetColor) {
return Color(
Blend.harmonize(targetColor.value, settings.value.sourceColor.value));
}
Color source(Color? target) {
Color source = settings.value.sourceColor;
if (target != null) {
source = blend(target);
}
return source;
}
ColorScheme colors(Brightness brightness, Color? targetColor) {
final dynamicPrimary = brightness == Brightness.light
? lightDynamic?.primary
: darkDynamic?.primary;
return ColorScheme.fromSeed(
seedColor: dynamicPrimary ?? source(targetColor),
brightness: brightness,
);
}
ShapeBorder get shapeMedium => RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
);
CardTheme cardTheme() {
return CardTheme(
elevation: 0,
shape: shapeMedium,
clipBehavior: Clip.antiAlias,
);
}
ListTileThemeData listTileTheme(ColorScheme colors) {
return ListTileThemeData(
shape: shapeMedium,
selectedColor: colors.secondary,
);
}
AppBarTheme appBarTheme(ColorScheme colors) {
return AppBarTheme(
elevation: 0,
backgroundColor: colors.surface,
foregroundColor: colors.onSurface,
);
}
TabBarTheme tabBarTheme(ColorScheme colors) {
return TabBarTheme(
labelColor: colors.secondary,
unselectedLabelColor: colors.onSurfaceVariant,
indicator: BoxDecoration(
border: Border(
bottom: BorderSide(
color: colors.secondary,
width: 2,
),
),
),
);
}
BottomAppBarTheme bottomAppBarTheme(ColorScheme colors) {
return BottomAppBarTheme(
color: colors.surface,
elevation: 0,
);
}
BottomNavigationBarThemeData bottomNavigationBarTheme(ColorScheme colors) {
return BottomNavigationBarThemeData(
type: BottomNavigationBarType.fixed,
backgroundColor: colors.surfaceContainerHighest,
selectedItemColor: colors.onSurface,
unselectedItemColor: colors.onSurfaceVariant,
elevation: 0,
landscapeLayout: BottomNavigationBarLandscapeLayout.centered,
);
}
NavigationRailThemeData navigationRailTheme(ColorScheme colors) {
return const NavigationRailThemeData();
}
DrawerThemeData drawerTheme(ColorScheme colors) {
return DrawerThemeData(
backgroundColor: colors.surface,
);
}
ThemeData light([Color? targetColor]) {
final colorScheme = colors(Brightness.light, targetColor);
return ThemeData.light(useMaterial3: true).copyWith(
pageTransitionsTheme: pageTransitionsTheme,
colorScheme: colorScheme,
appBarTheme: appBarTheme(colorScheme),
cardTheme: cardTheme(),
listTileTheme: listTileTheme(colorScheme),
bottomAppBarTheme: bottomAppBarTheme(colorScheme),
bottomNavigationBarTheme: bottomNavigationBarTheme(colorScheme),
navigationRailTheme: navigationRailTheme(colorScheme),
tabBarTheme: tabBarTheme(colorScheme),
drawerTheme: drawerTheme(colorScheme),
scaffoldBackgroundColor: colorScheme.surface,
);
}
ThemeData dark([Color? targetColor]) {
final colorScheme = colors(Brightness.dark, targetColor);
return ThemeData.dark(useMaterial3: true).copyWith(
pageTransitionsTheme: pageTransitionsTheme,
colorScheme: colorScheme,
appBarTheme: appBarTheme(colorScheme),
cardTheme: cardTheme(),
listTileTheme: listTileTheme(colorScheme),
bottomAppBarTheme: bottomAppBarTheme(colorScheme),
bottomNavigationBarTheme: bottomNavigationBarTheme(colorScheme),
navigationRailTheme: navigationRailTheme(colorScheme),
tabBarTheme: tabBarTheme(colorScheme),
drawerTheme: drawerTheme(colorScheme),
scaffoldBackgroundColor: colorScheme.surface,
);
}
ThemeMode themeMode() {
return settings.value.themeMode;
}
ThemeData theme(BuildContext context, [Color? targetColor]) {
final brightness = MediaQuery.of(context).platformBrightness;
return brightness == Brightness.light
? light(targetColor)
: dark(targetColor);
}
static ThemeProvider of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<ThemeProvider>()!;
}
@override
bool updateShouldNotify(covariant ThemeProvider oldWidget) {
return oldWidget.settings != settings;
}
}
class ThemeSettings {
ThemeSettings({
required this.sourceColor,
required this.themeMode,
});
final Color sourceColor;
final ThemeMode themeMode;
}
Color randomColor() {
return Color(Random().nextInt(0xFFFFFFFF));
}
// Custom Colors
const linkColor = CustomColor(
name: 'Link Color',
color: Color(0xFF00B0FF),
);
class CustomColor {
const CustomColor({
required this.name,
required this.color,
this.blend = true,
});
final String name;
final Color color;
final bool blend;
Color value(ThemeProvider provider) {
return provider.custom(this);
}
}
view raw theme.dart hosted with ❤ by GitHub
    Sekian implementasi dari Flutter Music App kali ini. Hope you enjoy and always be happy guys!!


                                                









Komentar

Postingan populer dari blog ini

Sejarah Mobile Phone dan Perkembangan Teknologinya

ViewModel & State Dalam Compose dengan Aplikasi Unscramble

Membuat Aplikasi Flutter Namer App