From 848e55d02760c06b6dbe4aa1e3679eac02e484bf Mon Sep 17 00:00:00 2001 From: misakajimmy Date: Thu, 16 Feb 2023 20:28:06 +0800 Subject: [PATCH] merge --- .github/workflows/app-prebuild.yml | 54 ------- .github/workflows/pre-build.yml | 116 ++++++++++++++ .github/workflows/prod-build.yml | 114 ++++++++++++++ README.md | 2 +- android/.gitignore | 1 - android/gradle/wrapper/key.properties | 4 + lib/routes/picture/pictureList.dart | 126 +++++++++++----- lib/routes/picture/pictureMemberFilter.dart | 20 ++- lib/routes/picture/picturePage.dart | 2 +- lib/routes/picture/pictureSwiper.dart | 159 +++++++++++--------- lib/routes/video/videoSwiper.dart | 4 +- pubspec.yaml | 3 +- 12 files changed, 425 insertions(+), 180 deletions(-) delete mode 100644 .github/workflows/app-prebuild.yml create mode 100644 .github/workflows/pre-build.yml create mode 100644 .github/workflows/prod-build.yml create mode 100644 android/gradle/wrapper/key.properties diff --git a/.github/workflows/app-prebuild.yml b/.github/workflows/app-prebuild.yml deleted file mode 100644 index 2a2c6bc..0000000 --- a/.github/workflows/app-prebuild.yml +++ /dev/null @@ -1,54 +0,0 @@ -# This is a basic workflow to help you get started with Actions - -name: EOEFANS PRE-BUIILD App CI - -# Controls when the workflow will run -on: - # Triggers the workflow on push or pull request events but only for the "main" branch - push: - branches: [ "main" ] -# pull_request: -# branches: [ "main" ] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -env: - ANDROID_KEY: ${{ secrets.ANDROID_KEY }} - KEY_PROPERTIES: ${{ secrets.KEY_PROPERTIES }} - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "build" - build: - # The type of runner that the job will run on - runs-on: [ self-hosted, Linux ] - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 - - - uses: actions/setup-java@v3 - with: - java-version: '11' - distribution: 'zulu' - - - name: Setup Android SDK - uses: android-actions/setup-android@v2 - - - uses: subosito/flutter-action@v2 - with: - channel: 'stable' # or: 'beta', 'dev' or 'master' - - - name: Set android sign key for app building - run: | - ls -la - cd android - touch key.pem && echo $ANDROID_KEY > key.pem - touch key.properties && echo $KEY_PROPERTIES > key.properties - - run: flutter pub get -# - run: flutter test - - run: flutter build apk - - run: ls -la - - run: tree . diff --git a/.github/workflows/pre-build.yml b/.github/workflows/pre-build.yml new file mode 100644 index 0000000..fed2d04 --- /dev/null +++ b/.github/workflows/pre-build.yml @@ -0,0 +1,116 @@ +# This is a basic workflow to help you get started with Actions + +name: EOEFANS PRE-BUILD App CI + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "main" branch + push: + branches: [ "main","ci" ] + # tags: [ "v*" ] +# pull_request: +# branches: [ "main","ci" ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + KEY_PROPERTIES: ${{ secrets.KEY_PROPERTIES }} + MY_JKS_FILE: ${{ secrets.MY_JKS_FILE }} + ACCOUNT_NAME: eoefans01 + ACCOUNT_KEY: ${{ secrets.STORAGE_ACCOUNT_KEY }} + SHARE_NAME: eoefans-client-dev # change for dev and prod + SHARE_NAME_PROD: eoefans-client # change for dev and prod + SOURCE_DIR: upload-ready + SOURCE_DIR_PROD: upload-ready-prod +# IMAGE_TAG: "" #we get tag using the action down below + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build-and-publish: + # The type of runner that the job will run on + runs-on: [ self-hosted, Linux ] + environment: + name: "Pre-build" + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + + - name: Get tag + if: startsWith(github.ref, 'refs/tags/') + id: tag + uses: dawidd6/action-get-tag@v1 + - name: set tag to env + if: startsWith(github.ref, 'refs/tags/') + run: | + echo "IMAGE_TAG=${{steps.tag.outputs.tag}}" >> $GITHUB_ENV + echo $GITHUB_ENV + + - uses: actions/setup-java@v3 + with: + distribution: "zulu" + java-version: "11" + cache: 'gradle' + + - name: Setup Android SDK + uses: android-actions/setup-android@v2 + + - name: Set android sign key for app building + run: | + echo "$KEY_PROPERTIES" > android/key.properties + echo "$MY_JKS_FILE" | base64 --decode > android/upload-keystore.jks + pwd $$ ls -la + - uses: subosito/flutter-action@v2 + with: + channel: 'stable' # or: 'beta', 'dev' or 'master' + cache: true + + - run: flutter pub get +# - run: flutter test + - run: flutter build apk + - name: list artifacts + run: | + ls -la + ls -la build/app/outputs/apk/release + + + + - name: move and rename artifacts + run: | + mkdir upload-ready + cp build/app/outputs/apk/release/* upload-ready + cd upload-ready && for file in *; do mv "$file" "${{ github.run_number }}-$file"; done && cd .. + ls -la upload-ready + - name: upload to azure file for dev environment + uses: cahaseler/azure-fileshare-upload@v1.0.0 + with: + account_name: ${{ env.ACCOUNT_NAME }} + account_key: ${{ env.ACCOUNT_KEY }} + share_name: ${{ env.SHARE_NAME }} + source_dir: ${{ env.SOURCE_DIR }} + + + + # - name: rename apk + # if: startsWith(github.ref, 'refs/tags/') + # run: | + # mkdir upload-ready-prod + # mv build/app/outputs/apk/release/app-release.apk upload-ready-prod/EOEFANS-${{ env.IMAGE_TAG }}.apk + + # - name: Publish release + # uses: softprops/action-gh-release@v1 + # if: startsWith(github.ref, 'refs/tags/') + # with: + # files: upload-ready-prod/EOEFANS-${{ env.IMAGE_TAG }}.apk + + # - name: upload to azure file for prod environment + # if: startsWith(github.ref, 'refs/tags/') + # uses: cahaseler/azure-fileshare-upload@v1.0.0 + # with: + # account_name: ${{ env.ACCOUNT_NAME }} + # account_key: ${{ env.ACCOUNT_KEY }} + # share_name: ${{ env.SHARE_NAME_PROD }} + # source_dir: ${{ env.SOURCE_DIR_PROD }} diff --git a/.github/workflows/prod-build.yml b/.github/workflows/prod-build.yml new file mode 100644 index 0000000..6dfead3 --- /dev/null +++ b/.github/workflows/prod-build.yml @@ -0,0 +1,114 @@ +# This is a basic workflow to help you get started with Actions + +name: EOEFANS PROD-BUILD App CI + +# Controls when the workflow will run +on: + # Triggers the workflow on push or pull request events but only for the "main" branch + push: + # branches: [ "main","ci" ] + tags: [ "v*" ] +# pull_request: +# branches: [ "main","ci" ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +env: + KEY_PROPERTIES: ${{ secrets.KEY_PROPERTIES }} + ACCOUNT_NAME: eoefans01 + ACCOUNT_KEY: ${{ secrets.STORAGE_ACCOUNT_KEY }} + SHARE_NAME: eoefans-client-dev # change for dev and prod + SHARE_NAME_PROD: eoefans-client # change for dev and prod + SOURCE_DIR: upload-ready + SOURCE_DIR_PROD: upload-ready-prod +# IMAGE_TAG: "" #we get tag using the action down below + +# A workflow run is made up of one or more jobs that can run sequentially or in parallel +jobs: + # This workflow contains a single job called "build" + build-and-publish: + # The type of runner that the job will run on + runs-on: [ self-hosted, Linux ] + environment: + name: "Prod-build" + + # Steps represent a sequence of tasks that will be executed as part of the job + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + + - name: Get tag + if: startsWith(github.ref, 'refs/tags/') + id: tag + uses: dawidd6/action-get-tag@v1 + - name: set tag to env + if: startsWith(github.ref, 'refs/tags/') + run: | + echo "IMAGE_TAG=${{steps.tag.outputs.tag}}" >> $GITHUB_ENV + echo $GITHUB_ENV + + - uses: actions/setup-java@v3 + with: + distribution: "zulu" + java-version: "11" + cache: 'gradle' + + - name: Setup Android SDK + uses: android-actions/setup-android@v2 + + - name: Set android sign key for app building + run: | + echo "$KEY_PROPERTIES" > android/key.properties + pwd $$ ls -la + - uses: subosito/flutter-action@v2 + with: + channel: 'stable' # or: 'beta', 'dev' or 'master' + cache: true + + - run: flutter pub get +# - run: flutter test + - run: flutter build apk + - name: list artifacts + run: | + ls -la + ls -la build/app/outputs/apk/release + + + + - name: move and rename artifacts + run: | + mkdir upload-ready + cp build/app/outputs/apk/release/* upload-ready + cd upload-ready && for file in *; do mv "$file" "${{ github.run_number }}-$file"; done && cd .. + ls -la upload-ready + - name: upload to azure file for dev environment + uses: cahaseler/azure-fileshare-upload@v1.0.0 + with: + account_name: ${{ env.ACCOUNT_NAME }} + account_key: ${{ env.ACCOUNT_KEY }} + share_name: ${{ env.SHARE_NAME }} + source_dir: ${{ env.SOURCE_DIR }} + + + + - name: rename apk + if: startsWith(github.ref, 'refs/tags/') + run: | + mkdir upload-ready-prod + mv build/app/outputs/apk/release/app-release.apk upload-ready-prod/EOEFANS-${{ env.IMAGE_TAG }}.apk + + - name: Publish release + uses: softprops/action-gh-release@v1 + if: startsWith(github.ref, 'refs/tags/') + with: + files: upload-ready-prod/EOEFANS-${{ env.IMAGE_TAG }}.apk + + - name: upload to azure file for prod environment + if: startsWith(github.ref, 'refs/tags/') + uses: cahaseler/azure-fileshare-upload@v1.0.0 + with: + account_name: ${{ env.ACCOUNT_NAME }} + account_key: ${{ env.ACCOUNT_KEY }} + share_name: ${{ env.SHARE_NAME_PROD }} + source_dir: ${{ env.SOURCE_DIR_PROD }} diff --git a/README.md b/README.md index d95cac8..77834a9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# eoe_fans +# EOEFANS A new Flutter project. diff --git a/android/.gitignore b/android/.gitignore index 6f56801..d5f967a 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -8,6 +8,5 @@ GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties **/*.keystore **/*.jks diff --git a/android/gradle/wrapper/key.properties b/android/gradle/wrapper/key.properties new file mode 100644 index 0000000..afb79bc --- /dev/null +++ b/android/gradle/wrapper/key.properties @@ -0,0 +1,4 @@ +storePassword=123abc456d +keyPassword=123abc456d +keyAlias=upload +storeFile=/runner/_work/eoefans-mobile-flutter/eoefans-mobile-flutter/android/upload-keystore.jks \ No newline at end of file diff --git a/lib/routes/picture/pictureList.dart b/lib/routes/picture/pictureList.dart index 19f3ea9..8b54231 100644 --- a/lib/routes/picture/pictureList.dart +++ b/lib/routes/picture/pictureList.dart @@ -8,6 +8,7 @@ import 'package:eoe_fans/routes/picture/pictureMemberFilter.dart'; import 'package:eoe_fans/routes/picture/pictureSwiper.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; class PictureList extends StatefulWidget { @@ -27,13 +28,35 @@ class _PictureListState extends State { bool _loading = false; MemberEnum? _memberFilter; List dynamicList = []; + List listWidgets = []; @override void initState() { _getPictures(); + _initListWidgets(); super.initState(); } + _initListWidgets() { + listWidgets = [ + StaggeredGridTile.count( + crossAxisCellCount: 4, + mainAxisCellCount: 1, + child: Center( + child: Container( + child: PictureMemberFilter( + filter: _memberFilter, + updateFilterMember: (MemberEnum? value) { + _memberFilter = value; + _reloadPictures(); + }, + ), + ), + ), + ) + ]; + } + _getPictures() async { setState(() { _loading = true; @@ -68,6 +91,24 @@ class _PictureListState extends State { if (pictures.result.length != 0) { setState(() { dynamicList = [...dynamicList, ...pictures.result]; + listWidgets = [ + ...listWidgets, + ...pictures.result.map( + (e) { + return StaggeredGridTile.count( + crossAxisCellCount: 2, + mainAxisCellCount: 3, + child: Card( + clipBehavior: Clip.antiAliasWithSaveLayer, + child: PictureSwiper( + dynamicId: e.dynamic_id.toString(), + images: e.pictures.map((e) => e.img_src).toList(), + ), + ), + ); + }, + ).toList() + ]; _loading = false; }); } else { @@ -79,6 +120,9 @@ class _PictureListState extends State { _reloadPictures({int? page}) async { dynamicList = []; + setState(() { + _initListWidgets(); + }); _page = page ?? 0; await _getPictures(); } @@ -121,45 +165,51 @@ class _PictureListState extends State { controller: _refreshController, onRefresh: _onRefresh, onLoading: _onLoading, - child: ListView.builder( - itemBuilder: (c, i) => Container( - child: i == 0 - ? SizedBox( - width: double.infinity, - height: 84, - child: PictureMemberFilter( - filter: _memberFilter, - updateFilterMember: (MemberEnum? value) { - _memberFilter = value; - _reloadPictures(); - }, - ), - ) - : SizedBox( - width: double.infinity, - height: 480, - child: Card( - clipBehavior: Clip.antiAliasWithSaveLayer, - child: PictureSwiper( - dynamicId: dynamicList[i].dynamic_id.toString(), - images: dynamicList[i] - .pictures - .map((e) => e.img_src) - .toList(), - ), - ), - ), - - // child: Center( - // child: Image( - // image: CachedNetworkImageProvider(dynamicList[i].pictures[0].img_src), - // fit: BoxFit.fitWidth, - // width: double.infinity, - // ), - // ), - ), - itemCount: dynamicList.length, + child: StaggeredGrid.count( + crossAxisCount: 4, + mainAxisSpacing: 4, + crossAxisSpacing: 4, + children: listWidgets, ), + // child: ListView.builder( + // itemBuilder: (c, i) => Container( + // child: i == 0 + // ? SizedBox( + // width: double.infinity, + // height: 84, + // child: PictureMemberFilter( + // filter: _memberFilter, + // updateFilterMember: (MemberEnum? value) { + // _memberFilter = value; + // _reloadPictures(); + // }, + // ), + // ) + // : SizedBox( + // width: double.infinity, + // height: 480, + // child: Card( + // clipBehavior: Clip.antiAliasWithSaveLayer, + // child: PictureSwiper( + // dynamicId: dynamicList[i].dynamic_id.toString(), + // images: dynamicList[i] + // .pictures + // .map((e) => e.img_src) + // .toList(), + // ), + // ), + // ), + // + // // child: Center( + // // child: Image( + // // image: CachedNetworkImageProvider(dynamicList[i].pictures[0].img_src), + // // fit: BoxFit.fitWidth, + // // width: double.infinity, + // // ), + // // ), + // ), + // itemCount: dynamicList.length, + // ), ); } } diff --git a/lib/routes/picture/pictureMemberFilter.dart b/lib/routes/picture/pictureMemberFilter.dart index 58c2295..7479fc5 100644 --- a/lib/routes/picture/pictureMemberFilter.dart +++ b/lib/routes/picture/pictureMemberFilter.dart @@ -26,12 +26,14 @@ class _PictureMemberFilterState extends State { @override Widget build(BuildContext context) { return Container( - child: GridView.count( - crossAxisCount: 5, - childAspectRatio: 1.0, - children: MemberEnum.values - .map( - (m) => GestureDetector( + child: Center( + child: GridView.count( + shrinkWrap: true, + crossAxisCount: 5, + childAspectRatio: 1.0, + children: MemberEnum.values + .map( + (m) => GestureDetector( onTap: () { setState(() { if (widget.filter == m) { @@ -79,7 +81,9 @@ class _PictureMemberFilterState extends State { ), ), ) - .toList(), - )); + .toList(), + ), + ), + ); } } diff --git a/lib/routes/picture/picturePage.dart b/lib/routes/picture/picturePage.dart index 54aee89..4360eb9 100644 --- a/lib/routes/picture/picturePage.dart +++ b/lib/routes/picture/picturePage.dart @@ -67,7 +67,7 @@ class _PicturePageState extends State { ), ), body: Container( - padding: const EdgeInsets.only(left: 4, right: 4, top: 8, bottom: 40), + padding: const EdgeInsets.only(left: 4, right: 4, bottom: 40), child: const TabBarView( children: [ PictureList(pageType: PicturePageType.recommend), diff --git a/lib/routes/picture/pictureSwiper.dart b/lib/routes/picture/pictureSwiper.dart index 76be036..98f2e2a 100644 --- a/lib/routes/picture/pictureSwiper.dart +++ b/lib/routes/picture/pictureSwiper.dart @@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:eoe_fans/routes/picture/pictureDetail.dart'; import 'package:extended_image/extended_image.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -13,89 +14,99 @@ class PictureSwiper extends StatelessWidget { @override Widget build(BuildContext context) { - return Stack( - children: [ - Swiper( - itemBuilder: (BuildContext context, int index) { - var image = CachedNetworkImageProvider(images[index]); - return Stack( - children: [ - Positioned( - top: 0, - bottom: 0, - left: 0, - right: 0, - child: GestureDetector( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - return PictureDetail(index: index, images: images); - }, + return GestureDetector( + onLongPress: () { + HapticFeedback.heavyImpact(); + // showMaterialModalBottomSheet( + // context: context, + // builder: (context) => Container(), + // ); + print('long press'); + }, + child: Stack( + children: [ + Swiper( + itemBuilder: (BuildContext context, int index) { + var image = CachedNetworkImageProvider(images[index]); + return Stack( + children: [ + Positioned( + top: 0, + bottom: 0, + left: 0, + right: 0, + child: GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) { + return PictureDetail(index: index, images: images); + }, + ), + ); + }, + child: Container( + child: ExtendedImage( + image: image, + fit: BoxFit.cover, ), - ); - }, - child: Container( - child: ExtendedImage( - image: image, - fit: BoxFit.cover, ), ), ), - ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - height: 40, - decoration: new BoxDecoration( - color: Color.fromRGBO(0, 0, 0, .3), - gradient: LinearGradient( - colors: [Colors.transparent, Colors.black], - begin: Alignment.topCenter, - end: Alignment.bottomCenter, + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + height: 40, + decoration: new BoxDecoration( + color: Color.fromRGBO(0, 0, 0, .3), + gradient: LinearGradient( + colors: [Colors.transparent, Colors.black], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + ), ), ), - ), - ) - ], - ); - }, - itemCount: images.length, - onTap: (int index) async {}, - pagination: const SwiperPagination( - alignment: Alignment.bottomLeft, - builder: DotSwiperPaginationBuilder( - color: Colors.white30, // 其他点的颜色 - activeColor: Colors.white, - space: 2, // 点与点之间的距离 - activeSize: 15, // 当前点的大小 + ) + ], + ); + }, + itemCount: images.length, + onTap: (int index) async {}, + pagination: const SwiperPagination( + alignment: Alignment.bottomLeft, + builder: DotSwiperPaginationBuilder( + color: Colors.white30, // 其他点的颜色 + activeColor: Colors.white, + space: 2, // 点与点之间的距离 + activeSize: 15, // 当前点的大小 + ), ), + autoplay: false, ), - autoplay: false, - ), - Positioned( - bottom: -4, - right: 8, - child: IconButton( - icon: Icon( - Icons.arrow_forward_ios, - size: 16, - color: Colors.white, - ), - onPressed: () async { - if (dynamicId != null) { - var _url = 'bilibili://following/detail/' + dynamicId!; - if (!await launchUrl(Uri.parse(_url))) { - throw 'Could not launch $_url'; + Positioned( + bottom: -4, + right: 8, + child: IconButton( + icon: Icon( + Icons.arrow_forward_ios, + size: 16, + color: Colors.white, + ), + onPressed: () async { + if (dynamicId != null) { + var _url = 'bilibili://following/detail/' + dynamicId!; + if (!await launchUrl(Uri.parse(_url))) { + throw 'Could not launch $_url'; + } } - } - }, - ), - ) - ], + }, + ), + ) + ], + ), ); } } diff --git a/lib/routes/video/videoSwiper.dart b/lib/routes/video/videoSwiper.dart index 66a92d2..659909d 100644 --- a/lib/routes/video/videoSwiper.dart +++ b/lib/routes/video/videoSwiper.dart @@ -3,13 +3,13 @@ import 'package:flutter_swiper_null_safety/flutter_swiper_null_safety.dart'; import 'package:url_launcher/url_launcher.dart'; const images = [ - 'assets/banner1.jpg', + 'assets/banner1.png', 'assets/banner2.png', 'assets/banner3.png', ]; const urls = [ - 'https://b23.tv/GI9EDCl', + 'https://b23.tv/KjrFIG1', 'bilibili://video/BV1Pv4y1C7TE', 'https://b23.tv/kI0MBkx' ]; diff --git a/pubspec.yaml b/pubspec.yaml index 26a5068..ae81660 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.6.0+1 +version: 1.6.2+1 environment: sdk: '>=2.18.6 <3.0.0' @@ -52,6 +52,7 @@ dependencies: extended_image: ^6.3.4 image_gallery_saver: ^1.7.1 fluttertoast: ^8.1.2 + modal_bottom_sheet: ^2.1.2 dev_dependencies: flutter_test: