





https://github.com

https://codeium.com

https://idx.google.com

MObile LEarning (mole)

Extension



main.dart
import 'package:flutter/material.dart'; Future<void> main() async { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'MOLE IT', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, ), home: const Home(), ); } } class Home extends StatelessWidget { const Home({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( color: Colors.purple, height: 100, width: double.infinity, child: const Center( child: Text('purple', style: TextStyle(color: Colors.white))), ), ], ), ); } }
Pecah menjadi 2 File
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( color: Colors.purple, height: 100, width: double.infinity, child: const Center( child: Text('purple', style: TextStyle(color: Colors.white))), ), ], ), ); } }
import 'package:flutter/material.dart'; import 'package:myapp/page/home.dart'; Future<void> main() async { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'MOLE IT', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, ), home: const Home(), ); } }
page/home.dart
main.dart
Color

import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), ), body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( color: Colors.purple, height: 100, width: double.infinity, child: const Center( child: Text('purple', style: TextStyle(color: Colors.white))), ), Container( color: Colors.blue.withOpacity(0.5), height: 100, width: double.infinity, child: const Center( child: Text('Blue with opacity', style: TextStyle(color: Colors.white))), ), Container( color: Colors.red.shade700, height: 100, width: double.infinity, child: const Center( child: Text('Red with shade 700', style: TextStyle(color: Colors.white))), ), Container( color: Colors.green[100], height: 100, width: double.infinity, child: const Center( child: Text('Green from palette', style: TextStyle(color: Colors.white))), ), Container( color: Colors.yellow[800], // Warna kuning dari palet dengan indeks 800 height: 100, width: double.infinity, child: const Center( child: Text('Yellow from palette', style: TextStyle(color: Colors.black))), ), ], ), ); } }
Text
import 'package:flutter/material.dart'; class Home extends StatelessWidget { const Home({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), ), body: const Padding( padding: EdgeInsets.all(16), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Normal Text', style: TextStyle(fontSize: 20), ), SizedBox(height: 20), Text( 'Bold Text', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), SizedBox(height: 20), Text( 'Italic Text', style: TextStyle(fontSize: 20, fontStyle: FontStyle.italic), ), SizedBox(height: 20), Text( 'Underlined Text', style: TextStyle(fontSize: 20, decoration: TextDecoration.underline), ), SizedBox(height: 20), Text( 'Text with Color', style: TextStyle(fontSize: 20, color: Colors.blue), ), SizedBox(height: 20), Text( 'Custom Font Family', style: TextStyle(fontSize: 20, fontFamily: 'arial'), ), ], ), ), ); } }

Splash Screen
upload image ke folder
assets/images/splash.png
aktifkan asset di file pubspec.yaml

Splash Screen

import 'package:flutter/material.dart'; class Splash extends StatefulWidget { const Splash({super.key}); @override State<Splash> createState() => _SplashState(); } class _SplashState extends State<Splash> { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: Container( margin: const EdgeInsets.all(16), decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/splash.png'), fit: BoxFit.contain, ), ), ), ); } }
Update
Tambahkan package get: ^4.6.6
import 'package:flutter/material.dart'; import 'package:get/get_navigation/src/root/get_material_app.dart'; import 'page/splash.dart'; Future<void> main() async { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return GetMaterialApp( debugShowCheckedModeBanner: false, title: 'MOLE IT', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, ), home: const Splash(), ); } }
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'home.dart'; class Splash extends StatefulWidget { const Splash({super.key}); @override State<Splash> createState() => _SplashState(); } class _SplashState extends State<Splash> { @override void initState() { super.initState(); Future.delayed(const Duration(seconds: 3), () { Get.off(const Home()); }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, body: Container( margin: const EdgeInsets.all(16), decoration: const BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/splash.png'), fit: BoxFit.contain, ), ), ), ); } }
page/splash.dart
main.dart
push to github
- initial repository
- commit
- publish branch







User Interface
tampilan visual sebuah produk yang menjembatani sistem dengan pengguna (user). Tampilan UI dapat berupa bentuk, warna, dan tulisan yang didesain semenarik mungkin. Secara sederhana, UI adalah bagaimana tampilan sebuah produk dilihat oleh pengguna.
User Experience
bagaimana pengalaman pengguna dalam berinteraksi/menggunakan produk digital Anda. Pengalaman ini dilihat dari betapa mudahnya pengguna untuk mendapatkan apa yang mereka inginkan dari produk tersebut. Dengan kata lain, user experience produk yang bagus tidak akan menyulitkan pengguna untuk mencapai tujuan mereka. Entah itu dari desain UI yang friendly, produk yang ringan untuk diakses, menu yang tidak berbelit-belit, dan lain sebagainya.
Perbedaan UI & UX


Menemukan Masalah:
Seorang UX Designer, akan memperhatikan perilaku pengemudi dan memahami bahwa tidaklah mudah untuk mengemudikan mobil dengan pasak kemudi itu. Hal ini menjadi perhatian UX designer

Evolusi kemudi mobil sebelum masa perang menjadi setir seperti yang sekarang kita kenal Dalam kasus setir mobil ini, UI designer akan bekerja sama dengan UX designer mendesain bagaimana antarmuka setir tersebut bisa berfungsi sesuai dengan konsep yang dikembangkan.
Laws of UX
kumpulan praktik terbaik yang dapat dipertimbangkan UI Designer saat membangun tampilan dari sebuah sistem. Hukum-hukum yang ada akan berkaitan satu sama lain untuk menunjang terwujudnya kepuasan pengguna
Aesthetic Usability Effect

Pengguna itu ternyata sering menganggap bahwa desain yang bermanfaat itu desain yang estetis. Jadi gampangnya, semakin estetis, semakin bermanfaat aplikasi tersebut. Desain yang lebih menyenangkan secara estetika itu dapat membuat pengguna lebih toleran terhadap masalah-masalah sepele di aplikasi tersebut.
Fitts Law

Hukum UX yang bernama Fitts’s Law ini menyatakan bahwa waktu untuk mendapatkan target adalah soal jarak ke target dan ukuran target. Artinya desain dari suatu tampilan harus mudah membuat penggunanya menemukan dan melakukan interaksi pada tools atau bagian tertentu yang dituju dalam waktu yang relatif cepat.

Goal-Gradient Effect

Sebuah tujuan akan cenderung lebih ingin dicapai ketika tujuan tersebut sudah berada lebih dekat.
Desain yang mendukung terwujudnya goal-gradient effect adalah dengan membuat tampilan yang merepresentasikan progress dan penyelesaian yang membuat pengguna termotivasi menyelesaikan aktivitas, contohnya adalah progress bar.
Hick’s Law

Hick’s Law ini menyatakan bahwa waktu yang diperlukan untuk membuat keputusan meningkat seiring dengan banyaknya jumlah dan kompleksitas pilihan
Jakob’s Law
Hukum yang satu ini menyatakan bahwa ternyata pengguna menghabiskan sebagian besar waktunya di aplikasi lain.Itu artinya pengguna lebih suka aplikasi yang kita buat bekerja dengan cara yang sama seperti semua aplikasi lain yang sudah mereka (pengguna) ketahui.

Doherty Threshold
Doherty Threshold hukum UX yang mengatakan kalau ternyata produktivitas bisa melonjak ketika komputer dan penggunanya berinteraksi dengan kecepatan kurang dari 400ms (millisecond).
Salah satu cara yang dapat dimanfaatkan untuk dapat membuat pengguna merasa lebih sabar untuk menunggu adalah dengan pemanfaatan animasi. Selain itu, tampilan progress bar dapat membantu toleransi waktu tunggu pengguna. Kamu bisa lihat grafik berikut

Occam’s Razor
hipotesis yang bersaing yang memprediksi dengan baik, yang memiliki asumsi paling sedikit harus dipilih. Maka dari itu, kamu sebaiknya analisis setiap elemen dan hapus sebanyak mungkin, tanpa mengganggu fungsinya secara keseluruhan.

Miller’s Law
Hukum ini cukup unik. Kok bisa? Ia mengatakan bahwa ternyata rata-rata orang hanya dapat menyimpan 7 (plus atau minus 2) item dalam memori kerja mereka.

Parkinson’s Law
Parkinson’s Law mencoba untuk menjelaskan kepada kita tentang pandangan pengguna dalam pengoperasian produk. Mencoba untuk mengerti atau menghitung jumlah waktu yang harus dikerjakan oleh user ketika melakukan pengoperasian produk yang telah kita desain. Semakin cepat mereka memahami semakin baik desain yang telah kita kerjakan.

Pareto Principle
Kalau konteksnya kita sedang membuat UX dalam sebuah aplikasi, maka fokuslah pada 20% dari keseluruhan fitur aplikasi tersebut. Dimana 20% fitur tersebut adalah fitur yang punya dampak paling besar.

Postel’s Law
Hukum yang namanya Postel’s Law mengatakan untuk liberal dalam apa yang kita terima, dan konservatif dalam apa yang kita kirim. Ketika kita membuat sebuah formulir untuk pengguna, kita harus menerima variabel jawaban tertentu dalam formulir tersebut.

Tesler’s Law
Setiap sistem itu ada sejumlah kompleksitas yang tidak bisa dikurangi. Terkadang untuk membuat desain yang bagus, maka designer perlu untuk membuat proses menjadi rumit, namun pengguna merasa tidak terlalu rumit dikarenakan adanya desain yang menarik.

Law of Common Region
Hukum ini mengatakan bahwa elemen dapat dikelompokkan jika mereka dibagi oleh area dengan batas yang jelas

Law of Proximity
objek/elemen yang berdekatan satu sama lain, cenderung dikelompokkan bersama.
Objek atau elemen yang saling berdekatan ini membantu pengguna dalam memahami dan mengatur informasi lebih cepat dan lebih efisien.

Law of Prägnanz
Hukum ini mengungkapkan bahwa mata manusia suka menemukan kesederhanaan dan ‘keteraturan dalam bentuk yang rumit’ karena mencegah kita dari kewalahan dengan informasi.

Law of Similarity
Mata manusia cenderung mempersepsikan elemen-elemen serupa dalam suatu desain sebagai gambar, bentuk, atau kelompok yang lengkap, bahkan jika elemen-elemen itu dipisahkan.

Law of Uniform Connectedness
hukum ini mengatakan kalau elemen yang terhubung secara visual itu dianggap lebih terkait/berhubungan daripada elemen tanpa koneksi.

Peak-End Rule
Ternyata pengguna itu cenderung menilai suatu pengalaman (experience) berdasarkan bagaimana perasaan mereka pada puncaknya (Peak moment) dan pada akhirnya (End moment), dibandingkan jumlah total atau rata-rata setiap momen pengalaman. Aplikasi Duolingo juga memberi selamat kepada pengguna untuk menjawab 10 pertanyaan dengan benar. Tentu pengalaman pengguna seperti ini yang tidak akan dilupakan.

Serial Position Effect
Pengguna memiliki kecenderungan untuk mengingat item pertama dan terakhir secara berurutan. Instagram, Twitter, Medium menempatkan 2 menu navigasi terpenting di pojok kanan dan pojok kiri. Di pojok kanan ada menu ‘Akun/profil’. Sedangkan di pojok kiri ada menu ‘Beranda’

Von Restorff Effect
Ketika beberapa objek serupa hadir, salah satu yang berbeda dari yang lain kemungkinan besar akan diingat.

Zeigarnik Effect
pengguna itu lebih gampang mengingat tugas/hal yang tidak selesai atau terganggu. Nah itulah kenapa kadang kalau kamu melakukan hal sesuatu di sebuah aplikasi itu ada ‘progress bar’-nya

Praktek Figma





pubspec.yaml
name: myapp description: "A new Flutter project." publish_to: 'none' version: 1.0.0+1 environment: sdk: ^3.5.3 dependencies: flutter: sdk: flutter get: ^4.6.6 cupertino_icons: ^1.0.8 dev_dependencies: flutter_test: sdk: flutter flutter: uses-material-design: true assets: - assets/images/ - assets/database.json
color.dart
const String appName = 'Mobile Learning';
const String imageSplash = 'assets/images/splash.png';app_config.dart
const String appName = 'Mobile Learning';
const String imageSplash = 'assets/images/splash.png';my_button.dart
import '../core.dart'; class MyButton extends StatelessWidget { final String buttonText; final Color buttonColor; final Color textColor; final VoidCallback? onPressed; const MyButton({ Key? key, required this.buttonText, this.buttonColor = primaryColor, this.textColor = whiteColor, this.onPressed, }) : super(key: key); @override Widget build(BuildContext context) { return ElevatedButton( onPressed: onPressed ?? () => Get.off(const Home()), // Default to navigating to Home style: ElevatedButton.styleFrom( backgroundColor: buttonColor, padding: const EdgeInsets.symmetric( horizontal: 32, vertical: 12, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text( buttonText, style: TextStyle( fontSize: 16, color: textColor, ), ), ); } }
my_card.dart
import '../core.dart'; class MyCard extends StatelessWidget { const MyCard({ super.key, required this.title, required this.description, required this.imagePath, // Add imagePath parameter }); final dynamic title; final dynamic description; final String imagePath; // Declare the imagePath parameter @override Widget build(BuildContext context) { return Card( color: whiteColor, elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( imagePath, // Use dynamic image path here width: 100, height: 100, ), const SizedBox(height: 10), Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), const SizedBox(height: 5), Text( description, style: const TextStyle( fontSize: 14, color: Colors.grey, ), textAlign: TextAlign.center, ), ], ), ); } }
my_container.dart
import '../core.dart'; class MyContainer extends StatelessWidget { final List<Widget> children; final Color? containerColor; // Added color parameter final EdgeInsetsGeometry? margin; // Added margin parameter final EdgeInsetsGeometry? padding; // Added padding parameter final BorderRadiusGeometry borderRadius; // Added dynamic borderRadius parameter final MainAxisAlignment? mainAxisAlignment; // Added dynamic mainAxisAlignment parameter final CrossAxisAlignment? crossAxisAlignment; // Added dynamic crossAxisAlignment parameter const MyContainer({ Key? key, required this.children, this.containerColor = Colors.white, // Default color is white this.margin = const EdgeInsets.all(16), // Default margin this.padding = const EdgeInsets.all(16), // Default padding this.borderRadius = const BorderRadius.all( Radius.circular(25)), // Default border radius is 25 for all corners this.mainAxisAlignment = MainAxisAlignment.start, // Default mainAxisAlignment is start this.crossAxisAlignment = CrossAxisAlignment.start, // Default crossAxisAlignment is start }) : super(key: key); @override Widget build(BuildContext context) { return Container( width: double.infinity, margin: margin, // Use dynamic margin here padding: padding, // Use dynamic padding here decoration: BoxDecoration( color: containerColor, // Use dynamic color here borderRadius: borderRadius, // Use dynamic border radius here ), child: Column( mainAxisAlignment: mainAxisAlignment ?? MainAxisAlignment.center, // Use dynamic mainAxisAlignment crossAxisAlignment: crossAxisAlignment ?? CrossAxisAlignment.center, // Use dynamic crossAxisAlignment children: children, ), ); } }
my_text.dart
import '../core.dart'; class MyText extends StatelessWidget { final String titleText; final TextStyle? titleStyle; final TextAlign textAlign; const MyText({ Key? key, required this.titleText, this.titleStyle, this.textAlign = TextAlign.left, // Default alignment is set to left }) : super(key: key); @override Widget build(BuildContext context) { return Text( titleText, textAlign: textAlign, style: titleStyle ?? const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black, ), ); } }
core.dart
export 'package:flutter/material.dart'; export 'package:get/get.dart'; export 'dart:convert'; export 'package:flutter/services.dart' show rootBundle; export 'utils/colors.dart'; export 'utils/app_config.dart'; export 'widget/my_text.dart'; export 'widget/my_button.dart'; export 'widget/my_container.dart'; export 'widget/my_card.dart'; export 'pages/splash.dart'; export 'pages/home.dart';
main.dart
import 'core.dart'; Future<void> main() async { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return GetMaterialApp( debugShowCheckedModeBanner: false, title: 'Mobile Learning', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: primaryColor), useMaterial3: true, ), home: const Splash(), ); } }
splash.dart
import '../core.dart'; class Splash extends StatelessWidget { const Splash({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: primaryColor, body: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Expanded( flex: 3, child: ImageSection(), ), Expanded( flex: 2, child: MainContainer(), ), ], ), ); } } class ImageSection extends StatelessWidget { const ImageSection({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Container( alignment: Alignment.center, child: Image.asset( imageSplash, fit: BoxFit.contain, ), ); } } class MainContainer extends StatelessWidget { const MainContainer({ super.key, }); @override Widget build(BuildContext context) { return MyContainer(children: [ Center( child: MyText( titleText: 'Discover your next skill\nLearn anything you want!', titleStyle: TextStyle( color: blackColor, fontSize: 24, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 5), Center( child: MyText( titleText: 'Discover your next skill\nLearn anything you want!', titleStyle: TextStyle( color: Colors.black54, fontSize: 16, fontWeight: FontWeight.normal, ), ), ), const SizedBox(height: 20), Center( child: MyButton( buttonText: 'Get Started', buttonColor: primaryColor, textColor: whiteColor, onPressed: () { Get.off(const Home()); }, ), ), ]); } }
home.dart
import '../core.dart'; class Home extends StatefulWidget { const Home({super.key}); @override _HomeState createState() => _HomeState(); } class _HomeState extends State<Home> { TextEditingController _searchController = TextEditingController(); List<dynamic> _filteredData = []; List<dynamic> _originalData = []; Future<List<dynamic>> loadJsonData() async { try { final String response = await rootBundle.loadString('assets/database.json'); return json.decode(response); } catch (error) { throw Exception('Failed to load JSON data: $error'); } } void _filterData(String query) { if (query.isEmpty || query.length < 3) { setState(() { // If query is less than 3 characters, show the original data _filteredData = _originalData; }); return; } setState(() { _filteredData = _originalData.where((item) { String title = item['title'] ?? ''; String description = item['description'] ?? ''; return title.toLowerCase().contains(query.toLowerCase()) || description.toLowerCase().contains(query.toLowerCase()); }).toList(); }); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: whiteColor, body: FutureBuilder<List<dynamic>>( future: loadJsonData(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } if (!snapshot.hasData || snapshot.data!.isEmpty) { return const Center(child: Text('No data available.')); } final List<dynamic> data = snapshot.data!; // Store original data to reset the filtered data when necessary _originalData = data; _filteredData = data; return Column( children: [ // Header Section with search input MyHeader( searchController: _searchController, onSearchChanged: _filterData), const SizedBox(height: 20), // Categories Section CategoryHeader(), CategoryBody(data: _filteredData), // Bottom Navigation Bar BottomNavBar(), ], ); }, ), ); } } class MyHeader extends StatelessWidget { const MyHeader({ super.key, required this.searchController, required this.onSearchChanged, }); final TextEditingController searchController; final Function(String) onSearchChanged; @override Widget build(BuildContext context) { return MyContainer( containerColor: primaryColor, margin: EdgeInsets.all(0), borderRadius: BorderRadius.only( bottomLeft: Radius.circular(25), bottomRight: Radius.circular(25), ), children: [ const SizedBox(height: 20), MyText( titleText: 'Hello', titleStyle: TextStyle( color: whiteColor, fontSize: 24, fontWeight: FontWeight.bold, ), ), MyText( titleText: 'Good Morning', titleStyle: TextStyle( color: whiteColor, fontSize: 18, fontWeight: FontWeight.normal, ), ), const SizedBox(height: 20), Container( padding: const EdgeInsets.symmetric(horizontal: 16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), ), child: TextField( controller: searchController, onChanged: onSearchChanged, decoration: InputDecoration( hintText: 'Search your topic', border: InputBorder.none, icon: Icon(Icons.search, color: Colors.grey[600]), ), ), ), ], ); } } class CategoryHeader extends StatelessWidget { const CategoryHeader({ super.key, }); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ MyText( titleText: 'Explore Categories', titleStyle: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), TextButton( onPressed: () { Get.snackbar(appName, 'Coming Soon'); }, child: const Text('See all'), ), ], ), ); } } class CategoryBody extends StatelessWidget { const CategoryBody({ super.key, required this.data, }); final List data; @override Widget build(BuildContext context) { return Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: GridView.builder( itemCount: data.length, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 16, mainAxisSpacing: 16, childAspectRatio: 0.75, ), itemBuilder: (context, index) { final program = data[index]; final title = program['title'] ?? 'No Title'; final description = program['description'] ?? '0 Courses'; return MyCard( title: title, description: description, imagePath: imageSplash, ); }, ), ), ); } } class BottomNavBar extends StatelessWidget { const BottomNavBar({ super.key, }); @override Widget build(BuildContext context) { return BottomNavigationBar( items: const [ BottomNavigationBarItem( icon: Icon(Icons.home), label: 'Home', ), BottomNavigationBarItem( icon: Icon(Icons.bookmark), label: 'Bookmark', ), BottomNavigationBarItem( icon: Icon(Icons.info), label: 'About', ), ], ); } }
database.json
[ { "title": "Pemrograman", "description": "5 Course", "image": "assets/images/splash.png", "course": [ { "title": "Mobile Learning", "description": "Mobile Learning", "image": "assets/images/splash.png", "chapter": [ { "title": "chapter 1", "description": "", "image": "assets/images/splash.png", "status": "active", "type": "pdf", "link_youtube": "", "link_pdf": "https://www.qeios.com/read/GKPOHZ/pdf" }, { "title": "chapter 2", "description": "", "image": "assets/images/splash.png", "status": "active", "type": "youtube", "link_youtube": "GSSzDIpyBuM", "link_pdf": "" } ] } ] }, { "title": "Bahasa", "description": "2 Course", "image": "assets/images/splash.png", "course": [ { "title": "Mobile Learning", "description": "Mobile Learning", "image": "assets/images/splash.png", "chapter": [ { "title": "chapter 1", "description": "", "image": "assets/images/splash.png", "status": "active", "type": "pdf", "link_youtube": "", "link_pdf": "https://www.qeios.com/read/GKPOHZ/pdf" }, { "title": "chapter 2", "description": "", "image": "assets/images/splash.png", "status": "active", "type": "youtube", "link_youtube": "GSSzDIpyBuM", "link_pdf": "" } ] } ] } ]
Mobile Learning
By Maulana Ilham
Mobile Learning
- 348