Sabtu, 22 Juni 2024

MUSIC APP

Nama : Naily Khairiya

NRP : 5025201244

Kelas : PPB - I


Pada blog ini, akan dibuat layar utama untuk aplikasi bernama MyArtist, sebuah aplikasi pemutar musik yang memungkinkan penggemar mengikuti berita terbaru dari artis favorit mereka. Bagian ini akan membahas bagaimana mengubah desain aplikasi Anda agar terlihat bagus di berbagai platform.


1. Mendapatkan kode awal

Untuk meng-clone codelab ini dari GitHub, jalankan perintah berikut:

git clone https://github.com/flutter/codelabs.git

cd codelabs/boring_to_beautiful/step_01/


2. Tipografi
Teks digunakan di berbagai tempat. Teks sangat berguna sebagai alat komunikasi kepada pengguna. Apakah aplikasi Anda ditujukan untuk memberikan kesan ramah dan menyenangkan, atau mungkin tepercaya dan profesional? Ada alasan mengapa aplikasi perbankan favorit Anda tidak menggunakan font Comic Sans. Tampilan teks membentuk kesan pertama pengguna tentang aplikasi Anda. Berikut beberapa cara untuk menggunakan teks dengan lebih cermat.  Di lib/src/shared/router.dart, tambahkan ikon utama yang berbeda untuk setiap tujuan navigasi (beranda, playlist, dan orang)

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',
 
),
];


Tambahkan font dengan $ flutter pub add google_fonts

4. Tema

Tema membantu menghadirkan desain dan keseragaman terstruktur ke aplikasi dengan menentukan sistem kumpulan warna dan gaya teks. Dengan tema, Anda dapat menerapkan UI dengan cepat tanpa harus pusing memikirkan detail kecil seperti menentukan warna yang tepat untuk setiap widget.

Contoh ini menggunakan penyedia tema yang terletakdi lib/src/shared/providers/theme.dart untuk membuat widget dan warna bertema konsisten di seluruh aplikasi:

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(
     
{Key? key,
     required
this.settings,
     required
this.lightDynamic,
     required
this.darkDynamic,
     required
Widget child})
     
: super(key: key, child: 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.surfaceVariant,
     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 _colors = colors(Brightness.light, targetColor);
   
return ThemeData.light().copyWith(
     pageTransitionsTheme
: pageTransitionsTheme,
     colorScheme
: _colors,
     appBarTheme
: appBarTheme(_colors),
     cardTheme
: cardTheme(),
     listTileTheme
: listTileTheme(_colors),
     bottomAppBarTheme
: bottomAppBarTheme(_colors),
     bottomNavigationBarTheme
: bottomNavigationBarTheme(_colors),
     navigationRailTheme
: navigationRailTheme(_colors),
     tabBarTheme
: tabBarTheme(_colors),
     drawerTheme
: drawerTheme(_colors),
     scaffoldBackgroundColor
: _colors.background,
     useMaterial3
: true,
   
);
 
}

 
ThemeData dark([Color? targetColor]) {
   
final _colors = colors(Brightness.dark, targetColor);
   
return ThemeData.dark().copyWith(
     pageTransitionsTheme
: pageTransitionsTheme,
     colorScheme
: _colors,
     appBarTheme
: appBarTheme(_colors),
     cardTheme
: cardTheme(),
     listTileTheme
: listTileTheme(_colors),
     bottomAppBarTheme
: bottomAppBarTheme(_colors),
     bottomNavigationBarTheme
: bottomNavigationBarTheme(_colors),
     navigationRailTheme
: navigationRailTheme(_colors),
     tabBarTheme
: tabBarTheme(_colors),
     drawerTheme
: drawerTheme(_colors),
     scaffoldBackgroundColor
: _colors.background,
     useMaterial3
: true,
   
);
 
}

 
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);
 
}
}


Untuk menggunakan penyedia tema, buat instance dan teruskan ke objek tema cakupan di MaterialApp, yang terletak di lib/src/shared/app.dart. Tema akan diwarisi oleh objek Theme bertingkat:

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';

class MyApp extends StatefulWidget {
 
const MyApp({Key? key}) : super(key: key);

 
@override
 
State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
 
final settings = ValueNotifier(ThemeSettings(
   sourceColor
:  Colors.pink,
   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); // Add this line
                 
return MaterialApp.router(
                   debugShowCheckedModeBanner
: false,
                   title
: 'Flutter Demo',
                   theme
: theme.light(settings.value.sourceColor), // Add this line
                   routeInformationParser
: appRouter.routeInformationParser,
                   routerDelegate
: appRouter.routerDelegate,
                 
);
               
},
             
),
           
)),
     
),
   
);
 
}
}


5. Desain Adaptif

Dengan Flutter, Anda dapat mem-build aplikasi yang berjalan hampir di mana saja. Namun, hal ini bukan berarti bahwa setiap aplikasi dapat berperilaku sama di semua layar perangkat. Pengguna mengharapkan perilaku dan fitur yang berbeda dari berbagai platform.

 File lib/src/shared/views/adaptive_navigation.dart berisi class navigasi tempat Anda dapat memberikan daftar tujuan dan konten untuk merender isi. Karena Anda menggunakan tata letak ini di beberapa layar, ada tata letak dasar bersama untuk diteruskan ke setiap turunan. Kolom samping navigasi cocok untuk desktop dan layar besar, tetapi jadikan tata letak tersebut mobile-friendly dengan menampilkan menu navigasi bawah di perangkat seluler.

import 'package:flutter/material.dart';

class AdaptiveNavigation extends StatelessWidget {
 
const AdaptiveNavigation({
   
Key? key,
    required
this.destinations,
    required
this.selectedIndex,
    required
this.onDestinationSelected,
    required
this.child,
 
}) : super(key: key);

 
final List<NavigationDestination> destinations;
 
final int selectedIndex;
 
final void Function(int index) onDestinationSelected;
 
final Widget child;

 
@override
 
Widget build(BuildContext context) {
   
return LayoutBuilder(
      builder
: (context, dimens) {
       
// Tablet Layout
       
if (dimens.maxWidth >= 600) { // Add this line
         
return Scaffold(
            body
: Row(
              children
: [
               
NavigationRail(
                  extended
: dimens.maxWidth >= 800,
                  minExtendedWidth
: 180,
                  destinations
: destinations
                     
.map((e) => NavigationRailDestination(
                            icon
: e.icon,
                            label
: Text(e.label),
                         
))
                     
.toList(),
                  selectedIndex
: selectedIndex,
                  onDestinationSelected
: onDestinationSelected,
               
),
               
Expanded(child: child),
             
],
           
),
         
);
       
} // Add this line

       
// Mobile Layout
       
// Add from here...
       
return Scaffold(
          body
: child,
          bottomNavigationBar
: NavigationBar(
            destinations
: destinations,
            selectedIndex
: selectedIndex,
            onDestinationSelected
: onDestinationSelected,
         
),
       
);
       
// ... To here.
     
},
   
);
 
}
}


6. Animasi 

Gerakan dan animasi adalah cara yang bagus untuk memberikan kesan aplikasi yang dinamis dan penuh semangat, serta untuk memberikan masukan saat pengguna berinteraksi dengan aplikasi.

ThemeProvider menentukan PageTransitionsTheme dengan animasi transisi layar untuk platform seluler (iOS, Android). Pengguna desktop sudah mendapatkan masukan dari klik mouse atau trackpad, sehingga animasi transisi halaman tidak diperlukan.

Flutter menyediakan animasi transisi layar yang dapat dikonfigurasikan untuk aplikasi Anda berdasarkan platform target seperti yang terlihat di lib/src/shared/providers/theme.dart:

final pageTransitionsTheme = const PageTransitionsTheme(
  builders
: <TargetPlatform, PageTransitionsBuilder>{
   
TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
   
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
   
TargetPlatform.linux: NoAnimationPageTransitionsBuilder(),
   
TargetPlatform.macOS: NoAnimationPageTransitionsBuilder(),
   
TargetPlatform.windows: NoAnimationPageTransitionsBuilder(),
 
},
);

Teruskan PageTransitionsTheme ke tema terang dan gelap pada lib/src/shared/providers/theme.dart

ThemeData light([Color? targetColor]) {
 
final _colors = colors(Brightness.light, targetColor);
 
return ThemeData.light().copyWith(
    pageTransitionsTheme
: pageTransitionsTheme, // Add this line
    colorScheme
: ColorScheme.fromSeed(
      seedColor
: source(targetColor),
      brightness
: Brightness.light,
   
),
    appBarTheme
: appBarTheme(_colors),
    cardTheme
: cardTheme(),
    listTileTheme
: listTileTheme(),
    tabBarTheme
: tabBarTheme(_colors),
    scaffoldBackgroundColor
: _colors.background,
 
);
}

ThemeData dark([Color? targetColor]) {
 
final _colors = colors(Brightness.dark, targetColor);
 
return ThemeData.dark().copyWith(
    pageTransitionsTheme
: pageTransitionsTheme, // Add this line
    colorScheme
: ColorScheme.fromSeed(
      seedColor
: source(targetColor),
      brightness
: Brightness.dark,
   
),
    appBarTheme
: appBarTheme(_colors),
    cardTheme
: cardTheme(),
    listTileTheme
: listTileTheme(),
    tabBarTheme
: tabBarTheme(_colors),
    scaffoldBackgroundColor
: _colors.background,
 
);
}


7. Jalankan aplikasi yang sudah dibuat

Aplikasi akan seperti berikut : 









Tidak ada komentar:

Posting Komentar

EAS PPB

Nama : Naily Khairiya NRP : 5025201244 Kelas : PPB - I JAWABAN EAS PPB Buat spesifikasi dan deskripsi aplikasi yang mampu dibuat berdasarkan...