今日要點
》前言
》介紹 FlutterEbookApp 專案
》下載並編譯 FlutterEbookApp 專案
》程式架構研究
最近 TikTok 很紅,所以本來想找類似的專案來看看,有找到三個,不過都有些要調整的地方,所以先轉移目標,今天找到一個 Ebook 類的專案,執行效果蠻不錯的,所以今天要來介紹它。
今天要介紹的Github專案,FlutterEbookApp 很不錯,他的書沒有版權的問題,所以他是真實可以用來閱讀電子書的專案,不是純UI 而己,而值得研究看看。JideGuru/FlutterEbookApp 637 的星星。
他在 README.md 有介紹很多執行的畫面,不過他其實在操作上有很多動畫,質感非常好。
所以我們就來練習編譯一下看看有沒有問題。
那麼我們就開始下載並且建立這個 FlutterEbookApp 專案囉。
% git clone https://github.com/JideGuru/FlutterEbookApp.git
Cloning into 'FlutterEbookApp'...
remote: Enumerating objects: 210, done.
remote: Counting objects: 100% (210/210), done.
remote: Compressing objects: 100% (125/125), done.
remote: Total 1487 (delta 107), reused 144 (delta 63), pack-reused 1277
Receiving objects: 100% (1487/1487), 69.01 MiB | 1.30 MiB/s, done.
Resolving deltas: 100% (830/830), done.
% cd FlutterEbookApp  
% flutter pub get
Running "flutter pub get" in FlutterEbookApp... 8.0s
試 build 一下,
% flutter run -d all

ok,一次成功 Android 執行起來了,iOS也OK。

不過 iOS 在下載完電子書後,點開閱讀時會出現錯誤,有空再來研究怎麼解決。Android 版則很順利的下載,閱讀。
裡面的文字還可以進行顏色標記,有點厲害,研究研究。
以下是 lib 裡的目錄,先列表起來, 之後再細看研究.
lib 目錄
| 目錄/檔案 | 檔案 | 備註 | 
|---|---|---|
| components | body_builder.dart | |
| book.dart | ||
| book_card.dart | ||
| book_list_item.dart | ||
| custom_alert.dart | ||
| description_text.dart | ||
| download_alert.dart | ||
| error_widget.dart | ||
| loading_widget.dart | ||
| theme | ||
| database | download_helper.dart | |
| favorite_helper.dart | ||
| locator_helper.dart | ||
| models | ||
| util | enum | |
| api.dart | ||
| consts.dart | ||
| dialogs.dart | ||
| functions.dart | ||
| router.dart | ||
| view_models | app_provider.dart | |
| details_provider.dart | ||
| favorites_provider.dart | ||
| genre_provider.dart | ||
| home_provider.dart | ||
| views | details | |
| downloads | ||
| explore | ||
| favorites | ||
| genre | ||
| home | ||
| main_screen.dart | ||
| settings | ||
| splash | ||
| main.dart | 
Main.dart : MaterialApp,Splash
在 VSCode 的樣子
在狀態變數上,我看到很熟悉的程式碼,MultiProvider 這個我有練習過,看到熟悉的程式碼真是讚。
void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => AppProvider()),
        ChangeNotifierProvider(create: (_) => HomeProvider()),
        ChangeNotifierProvider(create: (_) => DetailsProvider()),
        ChangeNotifierProvider(create: (_) => FavoritesProvider()),
        ChangeNotifierProvider(create: (_) => GenreProvider()),
      ],
      child: MyApp(),
    ),
  );
}
執行時先去 call 啟動畫面 Splash()。
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<AppProvider>(
      builder: (BuildContext context, AppProvider appProvider, Widget child) {
        return MaterialApp(
          key: appProvider.key,
          debugShowCheckedModeBanner: false,
          navigatorKey: appProvider.navigatorKey,
          title: Constants.appName,
          theme: themeData(appProvider.theme),
          darkTheme: themeData(ThemeConfig.darkTheme),
          home: Splash(),
        );
      },
    );
  }

splash.dart 主要是顯示啟動畫,然後轉到 MainScreen()去。
  changeScreen() async {
    MyRouter.pushPageReplacement(
      context,
      MainScreen(),
    );
  }

main_screen.dart 主要是一個 PageView ,然後下方一個 BottomNavigationBar。
        body: PageView(
          physics: NeverScrollableScrollPhysics(),
          controller: _pageController,
          onPageChanged: onPageChanged,
          children: <Widget>[
            Home(),
            Explore(),
            Profile(),
          ],
        ),
        bottomNavigationBar: BottomNavigationBar(...)
他用到的 plugin 都是很熱門的,是學習的好範例
- Provider : State Management
 - Object DB : NoSQL database to store Favorites & Downloads
 - XML2JSON : Convert XML to JSON
 - DIO : Network calls and File Download
 - EPub Viewer : A flutter plugin for Folioreader to read ePub files
 
今天就先這樣吧。
好,第26天,寫完。
參考