├── .gradle
├── 6.1.1
│ ├── gc.properties
│ ├── fileChanges
│ │ └── last-build.bin
│ └── fileHashes
│ │ └── fileHashes.lock
├── vcs-1
│ └── gc.properties
└── checksums
│ └── checksums.lock
├── _config.yml
├── android
├── settings_aar.gradle
├── gradle.properties
├── app
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ └── ic_launcher.png
│ │ │ │ ├── values
│ │ │ │ │ └── styles.xml
│ │ │ │ ├── drawable
│ │ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable-v21
│ │ │ │ │ └── launch_background.xml
│ │ │ │ └── values-night
│ │ │ │ │ └── styles.xml
│ │ │ └── kotlin
│ │ │ │ └── top
│ │ │ │ └── hanerx
│ │ │ │ └── flutterdmzj
│ │ │ │ └── MainActivity.kt
│ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── google-services.json
│ └── build.gradle
├── .gitignore
├── proguard-rules.pro
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── settings.gradle
└── build.gradle
├── assets
├── guide
│ ├── chapter0
│ │ ├── example0.json
│ │ ├── example1.json
│ │ └── example2.json
│ └── example.json
└── js
│ └── lzString.js
├── ios
├── Runner
│ ├── Runner-Bridging-Header.h
│ ├── Assets.xcassets
│ │ ├── LaunchImage.imageset
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ ├── README.md
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ ├── Icon-App-20x20@1x.png
│ │ │ ├── Icon-App-20x20@2x.png
│ │ │ ├── Icon-App-20x20@3x.png
│ │ │ ├── Icon-App-29x29@1x.png
│ │ │ ├── Icon-App-29x29@2x.png
│ │ │ ├── Icon-App-29x29@3x.png
│ │ │ ├── Icon-App-40x40@1x.png
│ │ │ ├── Icon-App-40x40@2x.png
│ │ │ ├── Icon-App-40x40@3x.png
│ │ │ ├── Icon-App-60x60@2x.png
│ │ │ ├── Icon-App-60x60@3x.png
│ │ │ ├── Icon-App-76x76@1x.png
│ │ │ ├── Icon-App-76x76@2x.png
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── Icon-App-83.5x83.5@2x.png
│ │ │ └── Contents.json
│ ├── AppDelegate.swift
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ └── Info.plist
├── Flutter
│ ├── Debug.xcconfig
│ ├── Release.xcconfig
│ └── AppFrameworkInfo.plist
├── Runner.xcodeproj
│ └── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── IDEWorkspaceChecks.plist
├── .gitignore
├── GoogleService-Info.plist
└── Podfile
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ └── Icon-512.png
├── manifest.json
└── index.html
├── doc
├── image-20210419184914844.png
├── image-20210419193403782.png
├── image-20210419193440494.png
└── image-20210419193540196.png
├── lib
├── protobuf
│ ├── comic.pbenum.dart
│ ├── novel_chapter.pbenum.dart
│ ├── comic.pbserver.dart
│ ├── novel_chapter.pbserver.dart
│ ├── novel_chapter.proto
│ └── comic.proto
├── model
│ ├── baseModel.dart
│ ├── mag_model
│ │ ├── OutputMangaModel.dart
│ │ └── MangaComicGroupModel.dart
│ ├── homepageModel.dart
│ ├── novel_source
│ │ └── baseNovelSourceModel.dart
│ ├── localHistoryModel.dart
│ ├── RouterModel.dart
│ ├── server_controller
│ │ ├── ComicListModel.dart
│ │ ├── UserListModel.dart
│ │ ├── ServerListModel.dart
│ │ ├── NewComicGroupModel.dart
│ │ ├── NewComicChapterModel.dart
│ │ └── ServerMainPageModel.dart
│ ├── download.dart
│ ├── comicSearchModel.dart
│ ├── comicLatestUpdateModel.dart
│ ├── sourceSearchProvider.dart
│ ├── comicCommentModel.dart
│ ├── cloudHistoryModel.dart
│ ├── subjectListModel.dart
│ ├── comicCategoryModel.dart
│ ├── comicAuthorModel.dart
│ ├── subjectDetailModel.dart
│ ├── comicFavoriteModel.dart
│ ├── trackerModel.dart
│ ├── novelFavoriteModel.dart
│ ├── comicCategoryDetailModel.dart
│ ├── databaseDetailModel.dart
│ └── downloadChapters.dart
├── http
│ ├── GithubRequestHandler.dart
│ ├── KuKuRequestHandler.dart
│ └── ManHuaGuiRequestHandler.dart
├── utils
│ ├── log_output.dart
│ ├── soup.dart
│ └── HttpProxyAdapter.dart
├── view
│ ├── comic_source
│ │ └── comic_source_page.dart
│ ├── history_page.dart
│ ├── settings
│ │ ├── user_setting_page.dart
│ │ └── source_setting_page.dart
│ ├── download_comic_page.dart
│ ├── favorite
│ │ ├── tracker_favorite_page.dart
│ │ ├── novel_favorite_page.dart
│ │ └── comic_favorite_page.dart
│ ├── novel_pages
│ │ ├── novel_main_page.dart
│ │ └── novel_category_page.dart
│ ├── download_page.dart
│ ├── mag_maker
│ │ ├── mag_example_page.dart
│ │ ├── new_mag_page.dart
│ │ └── output_mag_page.dart
│ ├── server_controllers
│ │ ├── server_sellect_page.dart
│ │ └── user_list_page.dart
│ ├── home_page.dart
│ ├── author_page.dart
│ ├── login_page.dart
│ ├── comment_page.dart
│ ├── favorite_page.dart
│ └── comic_pages
│ │ └── subject_list_page.dart
├── component
│ ├── ViewPointChip.dart
│ ├── LoadingCube.dart
│ ├── comic_viewer
│ │ ├── Common.dart
│ │ ├── EndPage.dart
│ │ └── Tips.dart
│ ├── comic
│ │ ├── BaseListTile.dart
│ │ └── SubjectListTile.dart
│ ├── DataBaseTable.dart
│ ├── search
│ │ ├── SearchButton.dart
│ │ └── SearchTab.dart
│ ├── CustomDrawer.dart
│ ├── TypeTags.dart
│ ├── DataBaseDefineTile.dart
│ ├── Authors.dart
│ ├── DownloadComicListTile.dart
│ ├── ComicSourceCard.dart
│ ├── CategoryCard.dart
│ ├── history_tab
│ │ └── LocalHistoryTab.dart
│ └── AuthorCard.dart
├── database
│ ├── tracker.dart
│ ├── cookieDatabaseProvider.dart
│ └── historyDatabaseProvider.dart
└── generated
│ └── intl
│ └── messages_all.dart
├── .metadata
├── .github
├── ISSUE_TEMPLATE
│ ├── ----.md
│ └── bug--.md
└── workflows
│ └── main.yml
├── .gitignore
└── test
└── widget_test.dart
/.gradle/6.1.1/gc.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gradle/vcs-1/gc.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gradle/6.1.1/fileChanges/last-build.bin:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-architect
--------------------------------------------------------------------------------
/android/settings_aar.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/assets/guide/chapter0/example0.json:
--------------------------------------------------------------------------------
1 | {
2 | "data": "hello world!"
3 | }
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/assets/guide/chapter0/example1.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test_manga",
3 | "title": "简单学会如何制作.manga文件"
4 | }
--------------------------------------------------------------------------------
/.gradle/checksums/checksums.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/.gradle/checksums/checksums.lock
--------------------------------------------------------------------------------
/doc/image-20210419184914844.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/doc/image-20210419184914844.png
--------------------------------------------------------------------------------
/doc/image-20210419193403782.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/doc/image-20210419193403782.png
--------------------------------------------------------------------------------
/doc/image-20210419193440494.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/doc/image-20210419193440494.png
--------------------------------------------------------------------------------
/doc/image-20210419193540196.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/doc/image-20210419193540196.png
--------------------------------------------------------------------------------
/.gradle/6.1.1/fileHashes/fileHashes.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/.gradle/6.1.1/fileHashes/fileHashes.lock
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.enableR8=true
3 | android.useAndroidX=true
4 | android.enableJetifier=true
5 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hanerx/dcomic/HEAD/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 | /test.properties
9 | /test.properties
10 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/assets/guide/chapter0/example2.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test_manga",
3 | "title": "简单学会如何制作.manga文件",
4 | "alias": [
5 | ".manga从入门到精通",
6 | ".manga Program design"
7 | ],
8 | "authors": [
9 | "hanerx"
10 | ]
11 | }
--------------------------------------------------------------------------------
/android/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | #Flutter Wrapper
2 | -keep class io.flutter.app.** { *; }
3 | -keep class io.flutter.plugin.** { *; }
4 | -keep class io.flutter.util.** { *; }
5 | -keep class io.flutter.view.** { *; }
6 | -keep class io.flutter.** { *; }
7 | -keep class io.flutter.plugins.** { *; }
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
7 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/lib/protobuf/comic.pbenum.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: comic.proto
4 | //
5 | // @dart = 2.12
6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
7 |
8 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 0b8abb4724aa590dd0f429683339b1e045a1594d
8 | channel: stable
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/lib/protobuf/novel_chapter.pbenum.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: novel_chapter.proto
4 | //
5 | // @dart = 2.12
6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields
7 |
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/----.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 功能需求
3 | about: 新功能的需求工单
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **需求简述**
11 | 需求的大概描述
12 |
13 | **需求主要目的与对应问题**
14 | 阐述需求主要是为了解决什么问题
15 |
16 | **需求主要功能清单**
17 | [ ] 功能1
18 | [ ] 功能2
19 | [x] 功能3
20 |
21 | **预期实现完成样式**
22 | *可以贴个图来说明到底要啥样子*
23 |
24 | **附加信息**
25 | *这里加上如参考的项目等附加信息*
26 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/lib/model/baseModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:dcomic/utils/log_output.dart';
3 | import 'package:logger/logger.dart';
4 |
5 | class BaseModel extends ChangeNotifier {
6 | Logger logger;
7 |
8 | BaseModel() {
9 | logger = Logger(
10 | filter: ReleaseFilter(),
11 | printer: PrettyPrinter(),
12 | output: ConsoleLogOutput());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/lib/protobuf/comic.pbserver.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: comic.proto
4 | //
5 | // @dart = 2.12
6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
7 |
8 | export 'comic.pb.dart';
9 |
10 |
--------------------------------------------------------------------------------
/lib/protobuf/novel_chapter.pbserver.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: novel_chapter.proto
4 | //
5 | // @dart = 2.12
6 | // ignore_for_file: annotate_overrides,camel_case_types,unnecessary_const,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type,unnecessary_this,prefer_final_fields,deprecated_member_use_from_same_package
7 |
8 | export 'novel_chapter.pb.dart';
9 |
10 |
--------------------------------------------------------------------------------
/lib/http/GithubRequestHandler.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/http/UniversalRequestModel.dart';
2 | import 'package:dio/dio.dart';
3 |
4 | class GithubRequestHandler extends SingleDomainRequestHandler {
5 | GithubRequestHandler() : super('https://api.github.com');
6 |
7 | Future getReleases() {
8 | return dio.get('/repos/hanerx/dcomic/releases');
9 | }
10 |
11 | Future getLatestRelease() {
12 | return dio.get('/repos/hanerx/flutter_dmzj/releases/latest');
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "LaunchImage.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "LaunchImage@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "LaunchImage@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
4 |
5 | def plugins = new Properties()
6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
7 | if (pluginsFile.exists()) {
8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
9 | }
10 |
11 | plugins.each { name, path ->
12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
13 | include ":$name"
14 | project(":$name").projectDir = pluginDirectory
15 | }
16 |
--------------------------------------------------------------------------------
/lib/utils/log_output.dart:
--------------------------------------------------------------------------------
1 | import 'package:logger/logger.dart';
2 | import 'package:logger_flutter/logger_flutter.dart';
3 |
4 | class ConsoleLogOutput extends ConsoleOutput {
5 | @override
6 | void output(OutputEvent event) {
7 | super.output(event);
8 | LogConsole.add(event);
9 | }
10 | }
11 |
12 | class ReleaseFilter extends LogFilter {
13 | @override
14 | bool shouldLog(LogEvent event) {
15 | var shouldLog = false;
16 | if (event.level.index >= level.index) {
17 | shouldLog = true;
18 | }
19 | return shouldLog;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dcomic",
3 | "short_name": "dcomic",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/lib/model/mag_model/OutputMangaModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/database/localMangaDatabaseProvider.dart';
2 | import 'package:dcomic/model/mag_model/baseMangaModel.dart';
3 | import 'package:firebase_crashlytics/firebase_crashlytics.dart';
4 |
5 | import '../baseModel.dart';
6 |
7 | class OutputMangaModel extends BaseModel{
8 | List _data=[];
9 |
10 | OutputMangaModel();
11 |
12 | Future init()async{
13 | try{
14 | _data=await LocalMangaDatabaseProvider().getAll();
15 | notifyListeners();
16 | }catch(e,s){
17 | FirebaseCrashlytics.instance
18 | .recordError(e, s, reason: 'localComicListInitFailed');
19 | }
20 | }
21 |
22 | List get data=>_data;
23 | }
--------------------------------------------------------------------------------
/lib/utils/soup.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:html/parser.dart' show parse;
3 | import 'package:html/dom.dart';
4 |
5 | class BeautifulSoup {
6 | String htmlDoc;
7 | Document doc;
8 | BeautifulSoup(this.htmlDoc){
9 | doc = parse(htmlDoc);
10 | }
11 |
12 | Element find({String id}) {
13 | return doc.querySelector(id);
14 | }
15 |
16 | Element call(String selector) => doc.querySelector(selector);
17 |
18 | List findAll(String selector){
19 | return doc.querySelectorAll(selector);
20 | }
21 |
22 | String getText(){
23 | return doc.querySelector("html").text;
24 | }
25 |
26 | String print(){
27 | return doc.querySelector("html").outerHtml;
28 | }
29 |
30 | String attr(Element e,String attribute) => e.attributes[attribute];
31 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .flutter-plugins-dependencies
28 | .packages
29 | .pub-cache/
30 | .pub/
31 | /build/
32 |
33 | # Web related
34 | lib/generated_plugin_registrant.dart
35 |
36 | # Exceptions to above rules.
37 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
38 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug--.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug报告
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Bug现象简述**
11 | A clear and concise description of what the bug is.
12 |
13 | **复现方法**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **预期动作**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **截图**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Smartphone (please complete the following information):**
27 | - Device: [e.g. iPhone6]
28 | - OS: [e.g. iOS8.1]
29 | - Browser [e.g. stock browser, safari]
30 | - Version [e.g. 22]
31 |
32 | **附加信息**
33 | Add any other context about the problem here.
34 |
--------------------------------------------------------------------------------
/lib/model/homepageModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/model/baseModel.dart';
2 | import 'package:dcomic/model/comic_source/baseSourceModel.dart';
3 | import 'package:firebase_crashlytics/firebase_crashlytics.dart';
4 |
5 | class HomepageModel extends BaseModel {
6 | final BaseSourceModel model;
7 | List _data = [];
8 | dynamic error;
9 |
10 | HomepageModel(this.model);
11 |
12 | Future init() async {
13 | try {
14 | _data = await model.homePageHandler.getHomePage();
15 | error = null;
16 | } catch (e, s) {
17 | FirebaseCrashlytics.instance
18 | .recordError(e, s, reason: 'getHomepageFailed');
19 | error = '未知错误:$e';
20 | }
21 | notifyListeners();
22 | }
23 |
24 | List get data => _data;
25 |
26 | int get length => _data.length;
27 | }
28 |
--------------------------------------------------------------------------------
/lib/model/novel_source/baseNovelSourceModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | import '../baseModel.dart';
4 |
5 | abstract class BaseNovelSourceModel extends BaseModel {
6 | Future> search(String keyword, {int page: 0});
7 |
8 | Widget getSettingWidget(context);
9 |
10 | }
11 |
12 | abstract class NovelDetail extends BaseModel{
13 |
14 | }
15 |
16 | abstract class Novel extends BaseModel{
17 |
18 | }
19 |
20 | abstract class NovelSearchResult {
21 | String get title;
22 |
23 | String get novelId;
24 |
25 | String get cover;
26 |
27 | String get author;
28 |
29 | String get tag;
30 |
31 | String get latestChapter;
32 |
33 | @override
34 | String toString() {
35 | return 'SearchResult{title: $title, novelId: $novelId, cover: $cover, author: $author, tag: $tag}';
36 | }
37 | }
--------------------------------------------------------------------------------
/lib/model/localHistoryModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/model/baseModel.dart';
2 | import 'package:dcomic/model/comic_source/baseSourceModel.dart';
3 | import 'package:dcomic/model/comic_source/sourceProvider.dart';
4 |
5 | class LocalHistoryModel extends BaseModel {
6 | final SourceProvider provider;
7 |
8 | LocalHistoryModel(this.provider);
9 |
10 | List _list = [];
11 |
12 | Future getHistories() async {
13 | for (var item in provider.activeSources) {
14 | _list += await item.getLocalHistoryComics();
15 | }
16 | _list.sort((left,right)=>right.timestamp.compareTo(left.timestamp));
17 | notifyListeners();
18 | }
19 |
20 | Future refresh() async {
21 | _list.clear();
22 | await getHistories();
23 | notifyListeners();
24 | }
25 |
26 | List get list => _list;
27 | }
28 |
--------------------------------------------------------------------------------
/lib/utils/HttpProxyAdapter.dart:
--------------------------------------------------------------------------------
1 | import 'dart:io';
2 |
3 | import 'package:dio/adapter.dart';
4 |
5 | class HttpProxyAdapter extends DefaultHttpClientAdapter {
6 | final String ipAddr;
7 | final int port;
8 |
9 | HttpProxyAdapter({this.ipAddr = 'localhost', this.port = 8888}) {
10 | onHttpClientCreate = (client) {
11 | String proxy = '$ipAddr:$port';
12 | client.findProxy = (url) {
13 | return 'PROXY $proxy';
14 | };
15 |
16 | client.badCertificateCallback =
17 | (X509Certificate cert, String host, int port) => true;
18 | };
19 | }
20 | }
21 |
22 | class BadCertificateAdapter extends DefaultHttpClientAdapter {
23 | BadCertificateAdapter() {
24 | onHttpClientCreate = (client) {
25 | client.badCertificateCallback =
26 | (X509Certificate cert, String host, int port) => true;
27 | };
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/model/RouterModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/model/baseModel.dart';
2 | import 'package:flutter/cupertino.dart';
3 |
4 | enum RouterLayout{
5 | RootRoute,
6 | HomeRoute,
7 | ViewerRoute
8 | }
9 |
10 | class RouterModel extends BaseModel{
11 | final GlobalKey homeNavigator=GlobalKey();
12 | final GlobalKey viewerNavigator=GlobalKey();
13 | final BuildContext context;
14 |
15 | RouterModel(this.context);
16 |
17 | NavigatorState getNavigatorState(RouterLayout layout){
18 | switch(layout){
19 | case RouterLayout.RootRoute:
20 | return Navigator.of(context);
21 | case RouterLayout.HomeRoute:
22 | return homeNavigator.currentState;
23 | case RouterLayout.ViewerRoute:
24 | return viewerNavigator.currentState;
25 | }
26 | return Navigator.of(context);
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 10.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/model/server_controller/ComicListModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/model/baseModel.dart';
2 | import 'package:dcomic/model/comic_source/IPFSSourceProivder.dart';
3 | import 'package:dcomic/model/comic_source/baseSourceModel.dart';
4 | import 'package:firebase_crashlytics/firebase_crashlytics.dart';
5 | import 'package:flutter/cupertino.dart';
6 |
7 | class ComicListModel extends BaseModel {
8 | final IPFSSourceModel node;
9 |
10 | List _data = [];
11 |
12 | TextEditingController controller=TextEditingController();
13 |
14 | ComicListModel(this.node);
15 |
16 | Future init() async {
17 | try {
18 | _data = await node.search(controller.text);
19 | notifyListeners();
20 | } catch (e, s) {
21 | FirebaseCrashlytics.instance.recordError(e, s,
22 | reason: 'comicListLoadingFailed: ${node.address}');
23 | }
24 | }
25 |
26 | List get data => _data;
27 | }
28 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.3.50'
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:3.5.4'
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 | classpath 'com.google.gms:google-services:4.3.4'
12 | classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1'
13 | classpath 'com.google.firebase:perf-plugin:1.3.2'
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | jcenter()
21 | maven { url 'https://jitpack.io' }
22 | }
23 | }
24 |
25 | rootProject.buildDir = '../build'
26 | subprojects {
27 | project.buildDir = "${rootProject.buildDir}/${project.name}"
28 | }
29 | subprojects {
30 | project.evaluationDependsOn(':app')
31 | }
32 |
33 | task clean(type: Delete) {
34 | delete rootProject.buildDir
35 | }
36 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 | import Firebase
4 | import flutter_downloader
5 |
6 | @UIApplicationMain
7 | @objc class AppDelegate: FlutterAppDelegate {
8 | override func application(
9 | _ application: UIApplication,
10 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
11 | ) -> Bool {
12 | GeneratedPluginRegistrant.register(with: self)
13 | FlutterDownloaderPlugin.setPluginRegistrantCallback(registerPlugins)
14 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
15 | }
16 |
17 | override func applicationDidFinishLaunching(_ application: UIApplication) {
18 | FirebaseApp.configure()
19 | }
20 |
21 | }
22 |
23 | private func registerPlugins(registry: FlutterPluginRegistry) {
24 | if (!registry.hasPlugin("FlutterDownloaderPlugin")) {
25 | FlutterDownloaderPlugin.register(with: registry.registrar(forPlugin: "FlutterDownloaderPlugin")!)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/model/download.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:dcomic/component/DownloadComicListTile.dart';
3 | import 'package:dcomic/database/downloader.dart';
4 | import 'package:dcomic/model/baseModel.dart';
5 |
6 | class DownloadModel extends BaseModel {
7 | List data;
8 |
9 |
10 | DownloadModel() {
11 | logger.i('action: init');
12 | getComic();
13 | }
14 |
15 | Future getComic() async {
16 | DownloadProvider downloadProvider = DownloadProvider();
17 | data = await downloadProvider.getAllComic();
18 | logger.i('action: getComic, comicList: $data');
19 | notifyListeners();
20 | }
21 |
22 | Widget buildComicListTile(context, index) {
23 | if (index < 0 || index >= data.length) {
24 | return null;
25 | }
26 | return DownloadComicListTile(
27 | title: data[index].title,
28 | comicId: data[index].comicId,
29 | cover: data[index].cover,
30 | );
31 | }
32 |
33 | int get length => data == null ? 0 : data.length;
34 | }
35 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/lib/view/comic_source/comic_source_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_easyrefresh/easy_refresh.dart';
4 | import 'package:dcomic/generated/l10n.dart';
5 | import 'package:dcomic/model/comic_source/sourceProvider.dart';
6 | import 'package:provider/provider.dart';
7 |
8 | class ComicSourcePage extends StatefulWidget {
9 | @override
10 | State createState() {
11 | // TODO: implement createState
12 | return _ComicSourcePage();
13 | }
14 | }
15 |
16 | class _ComicSourcePage extends State {
17 | @override
18 | Widget build(BuildContext context) {
19 | // TODO: implement build
20 | return Scaffold(
21 | appBar: AppBar(
22 | title: Text(S.of(context).SettingPageSourcePageSourceTitle),
23 | ),
24 | body: EasyRefresh(
25 | child: ListView.builder(
26 | itemBuilder: Provider.of(context).getSourceConfigWidget,
27 | itemCount: Provider.of(context).sources.length,
28 | )),
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/lib/view/history_page.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/cupertino.dart';
3 | import 'package:flutter/material.dart';
4 | import 'package:dcomic/component/history_tab/CloudHistoryTab.dart';
5 | import 'package:dcomic/component/history_tab/LocalHistoryTab.dart';
6 |
7 | class HistoryPage extends StatefulWidget {
8 | @override
9 | State createState() {
10 | // TODO: implement createState
11 | return _HistoryPage();
12 | }
13 | }
14 |
15 | class _HistoryPage extends State {
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | // TODO: implement build
20 | return DefaultTabController(
21 | length: 2,
22 | child: Scaffold(
23 | appBar: AppBar(
24 | title: Text('历史记录'),
25 | bottom: TabBar(
26 | tabs: [
27 | Tab(text:'云端记录'),
28 | Tab(text: '本地记录',)
29 | ],
30 | ),
31 | ),
32 | body:TabBarView(
33 | children: [
34 | CloudHistoryTab(),
35 | LocalHistoryTab()
36 | ],
37 | ),
38 | ),
39 | );
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/android/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "522563222655",
4 | "project_id": "dcomic-93209",
5 | "storage_bucket": "dcomic-93209.appspot.com"
6 | },
7 | "client": [
8 | {
9 | "client_info": {
10 | "mobilesdk_app_id": "1:522563222655:android:e14780753062c4cf43d34a",
11 | "android_client_info": {
12 | "package_name": "top.hanerx.flutterdmzj"
13 | }
14 | },
15 | "oauth_client": [
16 | {
17 | "client_id": "522563222655-vtsp4k0o2ef9gua3rgf01jl4u4hm791s.apps.googleusercontent.com",
18 | "client_type": 3
19 | }
20 | ],
21 | "api_key": [
22 | {
23 | "current_key": "AIzaSyB8rCCOBN1x2sC5VBnAEE_EhOBiCaC518A"
24 | }
25 | ],
26 | "services": {
27 | "appinvite_service": {
28 | "other_platform_oauth_client": [
29 | {
30 | "client_id": "522563222655-vtsp4k0o2ef9gua3rgf01jl4u4hm791s.apps.googleusercontent.com",
31 | "client_type": 3
32 | }
33 | ]
34 | }
35 | }
36 | }
37 | ],
38 | "configuration_version": "1"
39 | }
--------------------------------------------------------------------------------
/lib/view/settings/user_setting_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:dcomic/generated/l10n.dart';
4 | import 'package:dcomic/model/comic_source/sourceProvider.dart';
5 | import 'package:provider/provider.dart';
6 |
7 | class UserSettingPage extends StatefulWidget {
8 | @override
9 | State createState() {
10 | // TODO: implement createState
11 | return _UserSettingPage();
12 | }
13 | }
14 |
15 | class _UserSettingPage extends State {
16 | @override
17 | Widget build(BuildContext context) {
18 | // TODO: implement build
19 | return Scaffold(
20 | appBar: AppBar(
21 | title: Text(S.of(context).SettingPageMainUserTitle),
22 | ),
23 | body: ListView.builder(
24 | itemBuilder: (context, index) {
25 | return Provider.of(context, listen: false)
26 | .activeSources[index]
27 | .userConfig
28 | .getSettingWidget(context);
29 | },
30 | itemCount: Provider.of(context).activeSources.length,
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/component/ViewPointChip.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class ViewPointChip extends StatelessWidget {
5 | final String content;
6 | final String id;
7 | final int num;
8 |
9 | ViewPointChip({this.content, this.id, this.num});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | // TODO: implement build
14 | return Container(
15 | margin: EdgeInsets.all(3),
16 | child: TextButton(
17 | child: Chip(
18 | label: Text('$content'),
19 | avatar: CircleAvatar(
20 | child: Text('${num % 100}'),
21 | backgroundColor: Colors.blue[
22 | num ~/ 100 * 100 + 400 > 800 ? 800 : num ~/ 100 * 100 + 400],
23 | foregroundColor: Colors.white,
24 | )),
25 | style: ButtonStyle(padding: MaterialStateProperty.all(EdgeInsets.zero)),
26 | onPressed: () {},
27 | ),
28 | );
29 | }
30 |
31 | @override
32 | String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
33 | // TODO: implement toString
34 | return '{content: $content, id: $id, num: $num, color: ${num ~/ 100 * 100 + 400}}';
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_test/flutter_test.dart';
10 |
11 | import 'package:dcomic/main.dart';
12 |
13 | void main() {
14 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // // Build our app and trigger a frame.
16 | // await tester.pumpWidget(MyApp());
17 | //
18 | // // Verify that our counter starts at 0.
19 | // expect(find.text('0'), findsOneWidget);
20 | // expect(find.text('1'), findsNothing);
21 | //
22 | // // Tap the '+' icon and trigger a frame.
23 | // await tester.tap(find.byIcon(Icons.add));
24 | // await tester.pump();
25 | //
26 | // // Verify that our counter has incremented.
27 | // expect(find.text('0'), findsNothing);
28 | // expect(find.text('1'), findsOneWidget);
29 | });
30 | }
31 |
--------------------------------------------------------------------------------
/ios/GoogleService-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CLIENT_ID
6 | 522563222655-lihtg3bcqnrea6k9em6etm6cga1h0h8n.apps.googleusercontent.com
7 | REVERSED_CLIENT_ID
8 | com.googleusercontent.apps.522563222655-lihtg3bcqnrea6k9em6etm6cga1h0h8n
9 | API_KEY
10 | AIzaSyDzVZW34AMDmTRo4bfUSEoB_r9KWYm9aVg
11 | GCM_SENDER_ID
12 | 522563222655
13 | PLIST_VERSION
14 | 1
15 | BUNDLE_ID
16 | online.connlost.dcomic
17 | PROJECT_ID
18 | dcomic-93209
19 | STORAGE_BUCKET
20 | dcomic-93209.appspot.com
21 | IS_ADS_ENABLED
22 |
23 | IS_ANALYTICS_ENABLED
24 |
25 | IS_APPINVITE_ENABLED
26 |
27 | IS_GCM_ENABLED
28 |
29 | IS_SIGNIN_ENABLED
30 |
31 | GOOGLE_APP_ID
32 | 1:522563222655:ios:7afebe3677ee371343d34a
33 |
34 |
--------------------------------------------------------------------------------
/lib/model/comicSearchModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/model/baseModel.dart';
2 | import 'package:dcomic/model/comic_source/baseSourceModel.dart';
3 | import 'package:firebase_crashlytics/firebase_crashlytics.dart';
4 |
5 | class ComicSearchModel extends BaseModel {
6 | List _list = [];
7 | int page = 0;
8 | final BaseSourceModel model;
9 | final String keyword;
10 |
11 | ComicSearchModel(this.model, this.keyword);
12 |
13 | Future search(String keyword) async {
14 | if (keyword != null && keyword != '') {
15 | try {
16 | _list += await model.search(keyword, page: page);
17 | notifyListeners();
18 | } catch (e, s) {
19 | FirebaseCrashlytics.instance
20 | .recordError(e, s, reason: 'searchFailed: ${model.type.name}');
21 | logger.e('action: searchFailed, keyword: $keyword');
22 | }
23 | }
24 | }
25 |
26 | Future refresh() async {
27 | _list.clear();
28 | page = 0;
29 | await search(keyword);
30 | notifyListeners();
31 | }
32 |
33 | Future next() async {
34 | page++;
35 | await search(keyword);
36 | notifyListeners();
37 | }
38 |
39 | List get list => _list;
40 |
41 | int get length => _list.length;
42 | }
43 |
--------------------------------------------------------------------------------
/lib/view/download_comic_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:dcomic/model/downloadChapters.dart';
4 | import 'package:provider/provider.dart';
5 |
6 | class DownloadComicPage extends StatefulWidget {
7 | final String comicId;
8 | final String title;
9 |
10 | const DownloadComicPage({Key key, this.comicId, this.title})
11 | : super(key: key);
12 |
13 | @override
14 | State createState() {
15 | // TODO: implement createState
16 | return _DownloadComicPage();
17 | }
18 | }
19 |
20 | class _DownloadComicPage extends State {
21 | @override
22 | Widget build(BuildContext context) {
23 | // TODO: implement build
24 | return ChangeNotifierProvider(
25 | create: (_) => DownloadChaptersModel(widget.comicId),
26 | builder: (context, child) {
27 | return Scaffold(
28 | appBar: AppBar(
29 | title: Text('下载详情-${widget.title}'),
30 | ),
31 | body: ListView.builder(
32 | itemCount: Provider.of(context).length,
33 | itemBuilder: Provider.of(context)
34 | .buildChapterListTile),
35 | );
36 | },
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/model/comicLatestUpdateModel.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:dcomic/model/baseModel.dart';
3 | import 'package:dcomic/model/comicRankingListModel.dart';
4 | import 'package:dcomic/model/comic_source/baseSourceModel.dart';
5 | import 'package:firebase_crashlytics/firebase_crashlytics.dart';
6 |
7 | class ComicLatestUpdateModel extends BaseModel {
8 | final BaseSourceModel model;
9 | int page = 0;
10 | List _data = [];
11 |
12 | ComicLatestUpdateModel(this.model);
13 |
14 | getLatestList() async {
15 | try {
16 | _data += await model.homePageHandler.getLatestUpdate(page);
17 | notifyListeners();
18 | logger.i(
19 | 'class: ComicLatestUpdateModel,action: getLatestList, page: $page');
20 | } catch (e, s) {
21 | FirebaseCrashlytics.instance
22 | .recordError(e, s, reason: 'getLatestListFailed');
23 | logger.e(
24 | 'class: ComicLatestUpdateModel, action: getLatestListFailed, exception: $e');
25 | }
26 | }
27 |
28 | Future refresh() async {
29 | page = 0;
30 | _data.clear();
31 | await getLatestList();
32 | notifyListeners();
33 | }
34 |
35 | Future next() async {
36 | page++;
37 | await getLatestList();
38 | notifyListeners();
39 | }
40 |
41 | int get length => _data.length;
42 |
43 | List get data => _data;
44 | }
45 |
--------------------------------------------------------------------------------
/lib/model/server_controller/UserListModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/model/baseModel.dart';
2 | import 'package:dcomic/model/comic_source/IPFSSourceProivder.dart';
3 | import 'package:firebase_crashlytics/firebase_crashlytics.dart';
4 |
5 | class UserListModel extends BaseModel {
6 | final IPFSSourceModel node;
7 | List _data = [];
8 |
9 | UserListModel(this.node);
10 |
11 | Future init() async {
12 | try {
13 | var response = await node.handler.getUserList();
14 | if (response.statusCode == 200) {
15 | _data = response.data['data']
16 | .map((e) =>
17 | User(e['username'], e['nickname'], e['rights'], e['avatar']))
18 | .toList();
19 | notifyListeners();
20 | }
21 | } catch (e, s) {
22 | FirebaseCrashlytics.instance
23 | .recordError(e, s, reason: 'userLoadingFailed');
24 | }
25 | }
26 |
27 | List get data => _data;
28 | }
29 |
30 | class User {
31 | final String username;
32 | final String nickname;
33 | final List rights;
34 | final String avatar;
35 |
36 | User(this.username, this.nickname, this.rights, this.avatar);
37 |
38 | bool get admin {
39 | for (var item in rights) {
40 | if (item['right_num'] == 1) {
41 | return true;
42 | }
43 | }
44 | return false;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/model/sourceSearchProvider.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:dcomic/component/SearchDialog.dart';
4 | import 'package:dcomic/database/sourceDatabaseProvider.dart';
5 | import 'package:dcomic/model/baseModel.dart';
6 | import 'package:dcomic/model/comic_source/baseSourceModel.dart';
7 |
8 | class SourceSearchProvider extends BaseModel {
9 | final BaseSourceModel model;
10 | final String comicId;
11 | String _keyword;
12 | List _list = [];
13 |
14 | SourceSearchProvider(this.model, this._keyword, this.comicId);
15 |
16 | Future refresh() async {
17 | _list = await model.search(keyword);
18 | print(_list);
19 | notifyListeners();
20 | }
21 |
22 | Widget buildListTile(context, index) {
23 | if (index >= 0 && index < length) {
24 | var result=_list[index];
25 | return SearchListTile(result.cover, result.title, result.tag, result.comicId, result.author);
26 | }
27 | return null;
28 | }
29 |
30 | Future boundComicId(String boundId)async{
31 | await SourceDatabaseProvider.boundComic(model.type.name, comicId, boundId);
32 | }
33 |
34 | int get length => _list.length;
35 |
36 | String get keyword => _keyword;
37 |
38 | set keyword(String value) {
39 | _keyword = value;
40 | notifyListeners();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/model/comicCommentModel.dart:
--------------------------------------------------------------------------------
1 | import 'package:dcomic/model/baseModel.dart';
2 | import 'package:dcomic/model/comic_source/baseSourceModel.dart';
3 | import 'package:firebase_crashlytics/firebase_crashlytics.dart';
4 |
5 | class ComicCommentModel extends BaseModel {
6 | int page = 0;
7 | List _data = [];
8 | Map comments = {};
9 |
10 | String error;
11 |
12 | final ComicDetail detail;
13 |
14 | ComicCommentModel(this.detail);
15 |
16 | Future getComment(int page) async {
17 | if (detail != null) {
18 | try {
19 | _data += await detail.getComments(page);
20 | notifyListeners();
21 | } on UnimplementedError {
22 | error = "该源不支持评论查看";
23 | } catch (e, s) {
24 | FirebaseCrashlytics.instance.recordError(e, s,
25 | reason:
26 | 'getComicCommentFailed: ${detail != null ? detail.comicId : null}');
27 | error = "未知错误:$e";
28 | }
29 | } else {
30 | error = '未获得漫画源';
31 | }
32 | notifyListeners();
33 | }
34 |
35 | Future refresh() async {
36 | _data.clear();
37 | page = 0;
38 | await getComment(page);
39 | notifyListeners();
40 | }
41 |
42 | Future next() async {
43 | page++;
44 | await getComment(page);
45 | notifyListeners();
46 | }
47 |
48 | List get data => _data;
49 |
50 | int get length => _data.length;
51 | }
52 |
--------------------------------------------------------------------------------
/lib/component/LoadingCube.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_spinkit/flutter_spinkit.dart';
4 |
5 | class LoadingCube extends StatelessWidget {
6 | final Color textColor;
7 | final Color backgroundColor;
8 | final Color cubeColor;
9 |
10 | const LoadingCube({Key key, this.textColor, this.backgroundColor, this.cubeColor}) : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | // TODO: implement build
15 | return Container(
16 | width: double.infinity,
17 | height: double.infinity,
18 | child: Center(
19 | child: SizedBox(
20 | height: 200.0,
21 | width: 300.0,
22 | child: Card(
23 | color: backgroundColor,
24 | elevation: 0,
25 | child: Column(
26 | mainAxisAlignment: MainAxisAlignment.center,
27 | crossAxisAlignment: CrossAxisAlignment.center,
28 | children: [
29 | Container(
30 | width: 50.0,
31 | height: 50.0,
32 | child: SpinKitFadingCube(
33 | color: cubeColor==null?Theme.of(context).primaryColor:cubeColor,
34 | size: 25.0,
35 | ),
36 | ),
37 | Container(
38 | child: Text('加载中',style: TextStyle(color: textColor),),
39 | )
40 | ],
41 | ),
42 | ),
43 | )),
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/component/comic_viewer/Common.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:dcomic/component/LoadingCube.dart';
3 | import 'package:dcomic/component/comic_viewer/EndPage.dart';
4 |
5 | typedef BoolCallback = Future Function();
6 | typedef OnPageChangeCallback = void Function(int index);
7 |
8 | class Common {
9 | static Widget builder(BuildContext context, int index, int count,
10 | IndexedWidgetBuilder builder, bool left, bool right,
11 | {bool dense = false}) {
12 | print(
13 | "class: ComicCommon, action: buildPage, index: $index, count: $count");
14 | if(count==2){
15 | return LoadingCube();
16 | }
17 | if (index == 0) {
18 | if (!left) {
19 | return LoadingCube();
20 | } else {
21 | return EndPage();
22 | }
23 | } else if (count != null && index == count-1) {
24 | if (!right) {
25 | return LoadingCube();
26 | } else {
27 | return EndPage();
28 | }
29 | } else if (index > 0 && index < count) {
30 | return builder(context, index - 1);
31 | }
32 | return null;
33 | }
34 |
35 | static Widget builderVertical(BuildContext context, int index, int count,
36 | IndexedWidgetBuilder builder, bool left, bool right,
37 | {bool dense = false}){
38 | print(
39 | "class: ComicCommon, action: buildPage, index: $index, count: $count");
40 | if (index >= 0 && index < count) {
41 | return builder(context, index);
42 | }
43 | return null;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/view/favorite/tracker_favorite_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter_easyrefresh/easy_refresh.dart';
3 | import 'package:dcomic/component/EmptyView.dart';
4 | import 'package:dcomic/component/LoadingCube.dart';
5 | import 'package:dcomic/model/trackerModel.dart';
6 | import 'package:provider/provider.dart';
7 |
8 | class TrackerFavoritePage extends StatefulWidget {
9 | @override
10 | State createState() {
11 | // TODO: implement createState
12 | return _TrackerFavoritePage();
13 | }
14 | }
15 |
16 | class _TrackerFavoritePage extends State {
17 | @override
18 | Widget build(BuildContext context) {
19 | // TODO: implement build
20 | return EasyRefresh(
21 | scrollController: ScrollController(),
22 | onRefresh: () async {
23 | await Provider.of(context, listen: false).init();
24 | },
25 | firstRefresh: true,
26 | firstRefreshWidget: LoadingCube(),
27 | emptyWidget: Provider.of(context).empty?EmptyView():null,
28 | child: Container(
29 | padding: EdgeInsets.fromLTRB(2, 7, 2, 0),
30 | child: GridView.count(
31 | physics: NeverScrollableScrollPhysics(),
32 | shrinkWrap: true,
33 | crossAxisCount: 3,
34 | childAspectRatio: 0.6,
35 | children:
36 | Provider.of(context).getFavoriteWidget(context),
37 | )));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/model/cloudHistoryModel.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:dcomic/database/sourceDatabaseProvider.dart';
4 | import 'package:dcomic/http/UniversalRequestModel.dart';
5 | import 'package:dcomic/model/baseModel.dart';
6 |
7 | class CloudHistoryModel extends BaseModel {
8 | int _page = 0;
9 | List _data = [];
10 | String _uid = '';
11 | bool _login = false;
12 |
13 | Future initLoginState() async {
14 | _login =
15 | await SourceDatabaseProvider.getSourceOption('dmzj', 'login');
16 | if (_login) {
17 | _uid = await SourceDatabaseProvider.getSourceOption('dmzj', 'uid');
18 | }
19 | }
20 |
21 | Future getHistory() async {
22 | try {
23 | var response = await UniversalRequestModel.dmzjInterfaceRequestHandler
24 | .getHistory(_uid, _page);
25 | if (response.statusCode == 200) {
26 | var data = jsonDecode(response.data);
27 | _data += data;
28 | notifyListeners();
29 | }
30 | } catch (e) {
31 | logger.e(
32 | 'class: ${this.runtimeType}, action: getHistoryFailed, exception: $e');
33 | }
34 | }
35 |
36 | Future refresh() async {
37 | _page = 0;
38 | _data.clear();
39 | await initLoginState();
40 | await getHistory();
41 | notifyListeners();
42 | }
43 |
44 | Future next() async {
45 | _page++;
46 | await getHistory();
47 | notifyListeners();
48 | }
49 |
50 | bool get login => _login;
51 |
52 | List get data => _data;
53 |
54 | int get length => _data.length;
55 | }
56 |
--------------------------------------------------------------------------------
/lib/protobuf/novel_chapter.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | package dmzj.novel;
4 |
5 |
6 | message NovelChapterResponse {
7 | int32 Errno = 1;
8 | string Errmsg = 2;
9 | repeated NovelChapterVolumeResponse Data= 3;
10 | }
11 |
12 | message NovelChapterVolumeResponse {
13 | int32 VolumeId = 1;
14 | string VolumeName = 2;
15 | int32 VolumeOrder=3;
16 | repeated NovelChapterItemResponse Chapters=4;
17 | }
18 |
19 | message NovelChapterItemResponse {
20 | int32 ChapterId = 1;
21 | string ChapterName=2;
22 | int32 ChapterOrder = 3;
23 | }
24 |
25 |
26 | message NovelDetailResponse {
27 | int32 Errno = 1;
28 | string Errmsg = 2;
29 | NovelDetailInfoResponse Data= 3;
30 | }
31 |
32 | message NovelDetailInfoResponse {
33 | int32 NovelId = 1;
34 | string Name = 2;
35 | string Zone=3;
36 | string Status=4;
37 | string LastUpdateVolumeName=5;
38 | string LastUpdateChapterName=6;
39 | int32 LastUpdateVolumeId=7;
40 | int32 LastUpdateChapterId=8;
41 | int64 LastUpdateTime=9;
42 | string Cover=10;
43 | int32 HotHits=11;
44 | string Introduction=12;
45 | repeated string Types=13;
46 | string Authors=14;
47 | string FirstLetter=15;
48 | int32 SubscribeNum=16;
49 | int64 RedisUpdateTime=17;
50 | repeated NovelDetailInfoVolumeResponse Volume=18;
51 | }
52 |
53 | message NovelDetailInfoVolumeResponse {
54 | int32 VolumeId = 1;
55 | int32 LnovelId = 2;
56 | string VolumeName=3;
57 | int32 VolumeOrder=4;
58 | int64 Addtime=5;
59 | int32 SumChapters=6;
60 | }
--------------------------------------------------------------------------------
/lib/component/comic/BaseListTile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class BaseListTile extends StatelessWidget {
5 | final Widget leading;
6 | final List detail;
7 | final VoidCallback onPressed;
8 |
9 | const BaseListTile({Key key, this.leading, this.detail, this.onPressed})
10 | : super(key: key);
11 |
12 | @override
13 | Widget build(BuildContext context) {
14 | // TODO: implement build
15 | return InkWell(
16 | onTap: () {
17 | if (onPressed != null) {
18 | onPressed();
19 | }
20 | },
21 | child: Container(
22 | padding: EdgeInsets.fromLTRB(8, 8, 8, 0),
23 | child: Container(
24 | padding: EdgeInsets.only(bottom: 8),
25 | decoration: BoxDecoration(
26 | border: Border(
27 | bottom: BorderSide(color: Colors.grey.withOpacity(0.1)))),
28 | child: Row(
29 | crossAxisAlignment: CrossAxisAlignment.start,
30 | children: [
31 | ClipRRect(
32 | borderRadius: BorderRadius.circular(4),
33 | child: Container(width: 100, child: leading)),
34 | SizedBox(
35 | width: 12,
36 | ),
37 | Expanded(
38 | child: Column(
39 | crossAxisAlignment: CrossAxisAlignment.start,
40 | children: detail),
41 | )
42 | ],
43 | ),
44 | ),
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/top/hanerx/flutterdmzj/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package top.hanerx.flutterdmzj
2 |
3 | import android.view.KeyEvent
4 | import androidx.annotation.NonNull
5 | import io.flutter.embedding.android.FlutterActivity;
6 | import io.flutter.embedding.engine.FlutterEngine
7 | import io.flutter.plugin.common.EventChannel
8 | import io.flutter.plugins.GeneratedPluginRegistrant
9 |
10 |
11 | class MainActivity : FlutterActivity() {
12 | private val VOLUME_CHANNEL = "top.hanerx/volume";
13 | private var event: EventChannel.EventSink? = null;
14 | override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
15 | GeneratedPluginRegistrant.registerWith(flutterEngine);
16 | EventChannel(flutterEngine.dartExecutor.binaryMessenger, VOLUME_CHANNEL).setStreamHandler(object : EventChannel.StreamHandler {
17 | override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
18 | event = events!!;
19 | }
20 |
21 | override fun onCancel(arguments: Any?) {
22 | event = null;
23 | }
24 |
25 | });
26 | }
27 |
28 |
29 | override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
30 | if (this.event != null) {
31 | if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
32 | this.event!!.success(0);
33 | return true;
34 | } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
35 | this.event!!.success(1);
36 | return true;
37 | }
38 | }
39 | return super.onKeyDown(keyCode, event)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/component/DataBaseTable.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 |
4 | class DataBaseTable extends StatelessWidget {
5 | final List headers;
6 | final List