Browse Source

Merge branch 'hotfix/green-asp' of lyq/FlutterOSC into master

天问 1 year ago
parent
commit
adabedda29
45 changed files with 1542 additions and 1189 deletions
  1. 1 0
      .devcontainer/Dockerfile
  2. 45 0
      .devcontainer/devcontainer.json
  3. 0 0
      .flutter-plugins-dependencies
  4. 3 3
      .github/workflows/build.yml
  5. 1 0
      .gitignore
  6. 66 0
      .gitpod.Dockerfile
  7. 75 0
      .gitpod.yml
  8. 3 9
      android/app/build.gradle
  9. 4 10
      android/app/src/main/AndroidManifest.xml
  10. 1 9
      android/app/src/main/java/com/yubo/flutterosc/MainActivity.java
  11. 1 1
      android/build.gradle
  12. 2 0
      android/gradle.properties
  13. 1 1
      android/gradle/wrapper/gradle-wrapper.properties
  14. 13 0
      android/gradlew
  15. 30 40
      lib/main.dart
  16. 0 0
      lib/model/api.dart
  17. 1 1
      lib/model/constants.dart
  18. 7 7
      lib/model/user_info.dart
  19. 0 153
      lib/pages/AboutPage.dart
  20. 15 15
      lib/pages/CommonWebPage.dart
  21. 58 57
      lib/pages/DiscoveryPage.dart
  22. 63 62
      lib/pages/NewsListPage.dart
  23. 101 97
      lib/pages/PublishTweetPage.dart
  24. 14 15
      lib/pages/TestPage.dart
  25. 124 122
      lib/pages/TweetDetailPage.dart
  26. 121 122
      lib/pages/TweetsListPage.dart
  27. 3 3
      lib/pages/UserInfoDetailPage.dart
  28. 154 0
      lib/pages/about_page.dart
  29. 93 98
      lib/pages/black_house_page.dart
  30. 16 16
      lib/pages/login_page.dart
  31. 57 63
      lib/pages/my_info_page.dart
  32. 15 15
      lib/pages/news_detail_page.dart
  33. 47 47
      lib/pages/offline_activity_page.dart
  34. 32 32
      lib/pages/setting_page.dart
  35. 20 20
      lib/util/BlackListUtils.dart
  36. 11 11
      lib/util/DataUtils.dart
  37. 7 7
      lib/util/NetUtils.dart
  38. 4 4
      lib/util/Utf8Utils.dart
  39. 16 14
      lib/widgets/CircleImage.dart
  40. 8 8
      lib/widgets/CommonEndLine.dart
  41. 29 29
      lib/widgets/MyDrawer.dart
  42. 21 21
      lib/widgets/SlideView.dart
  43. 245 30
      pubspec.lock
  44. 13 46
      pubspec.yaml
  45. 1 1
      test/widget_test.dart

+ 1 - 0
.devcontainer/Dockerfile

@@ -0,0 +1 @@
+FROM jianboy/flutter-dev-container:3.0.5

+ 45 - 0
.devcontainer/devcontainer.json

@@ -0,0 +1,45 @@
+// java8 + android env
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
+// https://github.com/microsoft/vscode-dev-containers/tree/v0.233.0/containers/java-8
+{
+    "name": "Java 11",
+    "build": {
+        "dockerfile": "Dockerfile",
+        "args": {
+            // Use the VARIANT arg to pick a Debian OS version: buster, bullseye
+            // Use bullseye when running on local arm64/Apple Silicon.
+            "VARIANT": "buster",
+            // Options
+            "INSTALL_MAVEN": "true",
+            "INSTALL_GRADLE": "true",
+            "NODE_VERSION": "lts/*"
+        }
+    },
+    // Set *default* container specific settings.json values on container create.
+    "settings": {
+        "java.home": "/docker-java-home",
+        "java.import.gradle.java.home": "/usr/local/sdkman/candidates/java/current",
+        "java.configuration.runtimes": [
+            {
+                "default": true,
+                "name": "JavaSE-11",
+                "path": "/usr/local/sdkman/candidates/java/current"
+            }
+        ]
+    },
+    // Add the IDs of extensions you want installed when the container is created.
+    "extensions": [
+        "vscjava.vscode-java-pack",
+        "dart-code.dart-code",
+        "dart-code.flutter"
+    ],
+    // Use 'forwardPorts' to make a list of ports inside the container available locally.
+    // "forwardPorts": [],
+    // Use 'postCreateCommand' to run commands after the container is created.
+    // "postCreateCommand": "java -version",
+    // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
+    "remoteUser": "vscode",
+    "features": {
+        "docker-in-docker": "latest"
+    }
+}

File diff suppressed because it is too large
+ 0 - 0
.flutter-plugins-dependencies


+ 3 - 3
.github/workflows/build.yml

@@ -17,18 +17,18 @@ jobs:
         uses: actions/setup-java@v2
         with:
           distribution: 'adopt'
-          java-version: "8.x"
+          java-version: "11"
 
       - name: Setup gradle
         uses: eskatos/gradle-command-action@v1
         with:
-          gradle-version: 6.5
+          gradle-version: 7.3.3
 
       - name: Flutter action
         uses: subosito/flutter-action@v1.5.3
         with:
           channel: "stable"
-          flutter-version: "2.0.5"
+          flutter-version: "3.0.5"
       
       - name: Cache Dependencies
         id: cache

+ 1 - 0
.gitignore

@@ -8,3 +8,4 @@ build/
 ios/.generated/
 packages
 .flutter-plugins
+.dart_tool/

+ 66 - 0
.gitpod.Dockerfile

@@ -0,0 +1,66 @@
+FROM gitpod/workspace-full-vnc
+SHELL ["/bin/bash", "-c"]
+
+ENV ANDROID_HOME=/home/gitpod/androidsdk \
+    FLUTTER_VERSION=2.10.5-stable
+
+# Install dart
+USER root
+RUN curl -fsSL https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
+    && curl -fsSL https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list \
+    && install-packages build-essential dart libkrb5-dev gcc make gradle android-tools-adb android-tools-fastboot
+
+# Install flutter
+USER gitpod
+RUN cd /home/gitpod \
+    && wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}.tar.xz \
+    && tar -xvf flutter*.tar.xz \
+    && rm -f flutter*.tar.xz
+
+RUN flutter/bin/flutter precache
+RUN echo 'export PATH="$PATH:/home/gitpod/flutter/bin"' >> /home/gitpod/.bashrc
+
+# Install Open JDK
+USER gitpod
+RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && \
+    sdk install java 11.0.16-amzn && \
+    sdk default java 11.0.16-amzn"
+
+# Install SDK Manager
+USER gitpod
+RUN  wget https://dl.google.com/android/repository/commandlinetools-linux-7583922_latest.zip \
+    && mkdir -p $ANDROID_HOME/cmdline-tools/latest \
+    && unzip commandlinetools-linux-*.zip -d $ANDROID_HOME \
+    && rm -f commandlinetools-linux-*.zip \
+    && mv $ANDROID_HOME/cmdline-tools/bin $ANDROID_HOME/cmdline-tools/latest \
+    && mv $ANDROID_HOME/cmdline-tools/lib $ANDROID_HOME/cmdline-tools/latest
+
+RUN echo "export ANDROID_HOME=$ANDROID_HOME" >> /home/gitpod/.bashrc \
+    && echo 'export PATH=$ANDROID_HOME/emulator:$ANDROID_HOME/tools:$ANDROID_HOME/cmdline-tools/bin:$ANDROID_HOME/platform-tools:$PATH' >> /home/gitpod/.bashrc
+
+# Install Android Image version 30
+USER gitpod
+RUN yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "platform-tools" "platforms;android-30" "emulator"
+RUN yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "system-images;android-30;google_apis;x86_64"
+RUN echo no | $ANDROID_HOME/cmdline-tools/latest/bin/avdmanager create avd -n avd28 -k "system-images;android-30;google_apis;x86_64"
+
+
+# Install Google Chrome
+USER root
+RUN apt-get update \
+  && apt-get install -y apt-transport-https \
+  && curl -sSL https://dl.google.com/linux/linux_signing_key.pub | apt-key add - \
+  && echo "deb [arch=amd64] https://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
+  && apt-get update \
+  && sudo apt-get install -y google-chrome-stable
+
+# misc deps
+RUN apt-get install -y \
+  libasound2-dev \
+  libgtk-3-dev \
+  libnss3-dev \
+  fonts-noto \
+  fonts-noto-cjk
+
+# For Qt WebEngine on docker
+ENV QTWEBENGINE_DISABLE_SANDBOX 1

+ 75 - 0
.gitpod.yml

@@ -0,0 +1,75 @@
+image:
+  file: .gitpod.Dockerfile
+tasks:
+  - before: sudo mount -t tmpfs shm -osize=4096m /dev/shm
+  - init: |
+      flutter channel beta
+      flutter upgrade
+
+      # flutter config --enable-web
+      flutter config --android-sdk /home/gitpod/androidsdk
+      yes | flutter doctor --android-licenses
+
+      # flutter doctor
+
+      # flutter pub get
+
+      # flutter build -v bundle
+      # flutter build -v web
+      # flutter build -v appbundle
+      # flutter build -v apk
+      
+  # - command: |
+  #     # Gitpod is not able to run emulators within a worspace at this stage as
+  #     # Google Kubernetes Engine does not support Nested Virtualization.
+  #     #
+  #     # If running Gitpod on your own infrastructure or via the Dockerfile locally
+  #     # on infrastructure that exposes vmx or svm then this command will launch
+  #     # the emulator.
+  #     #
+  #     # $ emulator -avd avd28 -no-audio -no-window 
+  #     #
+  #     # Until this restriction is mitigated you can run native mobile apps in your
+  #     # browser via https://appetize.io/
+
+  #     if [[ -z "$APPETIZE_API_TOKEN" ]]; then
+  #         echo "Appetize API token not set. Run:"
+  #         echo ""
+  #         echo "    gp env APPETIZE_API_TOKEN=your_token"
+  #         echo ""
+  #         echo "and restart this workspace in order to get an app preview."
+  #         echo ""
+  #         echo "Request your token here: https://appetize.io/docs#request-api-token"
+  #     else
+  #         curl -sS --http1.1 "https://$APPETIZE_API_TOKEN@api.appetize.io/v1/apps/$APPETIZE_PUBLICKEY" \
+  #             -F "file=@/workspace/template-flutter/build/app/outputs/flutter-apk/app.apk" \
+  #             -F platform=android \
+  #             -F "buttonText=Start App" \
+  #             -F "postSessionButtonText=Start App" \
+  #             > .appetize.json
+
+  #         APPETIZE_PUBLICKEY=$(jq -r .publicKey .appetize.json)
+  #         gp env "APPETIZE_PUBLICKEY=$APPETIZE_PUBLICKEY"
+  #         export APPETIZE_PUBLICKEY
+
+  #         python -m webbrowser "https://appetize.io/embed/$APPETIZE_PUBLICKEY?device=pixel4&autoplay=true"
+  #     fi
+
+  #     flutter devices
+    
+  #     flutter run --web-port 8080
+
+
+ports:
+  - port: 5900
+    onOpen: ignore
+    # vnc
+  - port: 6080
+    onOpen: open-preview
+    # flutter
+  - port: 8080
+    onOpen: open-preview
+
+vscode:
+  extensions:
+    - dart-code.flutter

+ 3 - 9
android/app/build.gradle

@@ -19,7 +19,7 @@ def keystoreProperties = new Properties()
 keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
 
 android {
-    compileSdkVersion 28
+    compileSdkVersion 31
 
     lintOptions {
         disable 'InvalidPackage'
@@ -27,8 +27,8 @@ android {
 
     defaultConfig {
         applicationId "com.yubo.flutterosc"
-        minSdkVersion 16
-        targetSdkVersion 28
+        minSdkVersion 18
+        targetSdkVersion 31
         versionCode 2
         versionName "1.0.1"
         testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -52,9 +52,3 @@ android {
 flutter {
     source '../..'
 }
-
-dependencies {
-//    testImplementation 'junit:junit:4.12'
-//    androidTestImplementation 'com.android.support.test:runner:1.0.1'
-//    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
-}

+ 4 - 10
android/app/src/main/AndroidManifest.xml

@@ -1,20 +1,11 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.yubo.flutterosc">
 
-    <!-- The INTERNET permission is required for development. Specifically,
-         flutter needs it to communicate with the running application
-         to allow setting breakpoints, to provide hot reload, etc.
-    -->
     <uses-permission android:name="android.permission.INTERNET"/>
     <uses-permission android:name="android.permission.CAMERA" />
 
-    <!-- io.flutter.app.FlutterApplication is an android.app.Application that
-         calls FlutterMain.startInitialization(this); in its onCreate method.
-         In most cases you can leave this as-is, but you if you want to provide
-         additional functionality it is fine to subclass or reimplement
-         FlutterApplication and put your custom class here. -->
+
     <application
-        android:name="io.flutter.app.FlutterApplication"
         android:label="flutter_osc"
         android:icon="@mipmap/ic_launcher">
         <activity
@@ -37,5 +28,8 @@
             </intent-filter>
         </activity>
         <activity android:name="com.apptreesoftware.barcodescan.BarcodeScannerActivity"/>
+        <meta-data
+            android:name="flutterEmbedding"
+            android:value="2" />
     </application>
 </manifest>

+ 1 - 9
android/app/src/main/java/com/yubo/flutterosc/MainActivity.java

@@ -1,14 +1,6 @@
 package com.yubo.flutterosc;
 
-import android.os.Bundle;
-
-import io.flutter.app.FlutterActivity;
-import io.flutter.plugins.GeneratedPluginRegistrant;
+import io.flutter.embedding.android.FlutterActivity;
 
 public class MainActivity extends FlutterActivity {
-  @Override
-  protected void onCreate(Bundle savedInstanceState) {
-    super.onCreate(savedInstanceState);
-    GeneratedPluginRegistrant.registerWith(this);
-  }
 }

+ 1 - 1
android/build.gradle

@@ -5,7 +5,7 @@ buildscript {
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.4.2'
+        classpath 'com.android.tools.build:gradle:7.2.2'
     }
 }
 

+ 2 - 0
android/gradle.properties

@@ -1 +1,3 @@
 org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true

+ 1 - 1
android/gradle/wrapper/gradle-wrapper.properties

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip

+ 13 - 0
android/gradlew

@@ -0,0 +1,13 @@
+#!/bin/sh
+# This is a generated file; do not edit or check into version control.
+export "FLUTTER_ROOT=/home/lyq/flutter"
+export "FLUTTER_APPLICATION_PATH=/home/lyq/workspaces/FlutterOSC"
+export "COCOAPODS_PARALLEL_CODE_SIGN=true"
+export "FLUTTER_TARGET=lib/main.dart"
+export "FLUTTER_BUILD_DIR=build"
+export "FLUTTER_BUILD_NAME=1.0.0"
+export "FLUTTER_BUILD_NUMBER=1"
+export "DART_OBFUSCATION=false"
+export "TRACK_WIDGET_CREATION=false"
+export "TREE_SHAKE_ICONS=false"
+export "PACKAGE_CONFIG=.dart_tool/package_config.json"

+ 30 - 40
lib/main.dart

@@ -3,29 +3,29 @@ import 'package:flutter/material.dart';
 import 'pages/NewsListPage.dart';
 import 'pages/TweetsListPage.dart';
 import 'pages/DiscoveryPage.dart';
-import 'pages/MyInfoPage.dart';
+import 'pages/my_info_page.dart';
 import './widgets/MyDrawer.dart';
 
 void main() {
-  runApp(new MyOSCClient());
+  runApp(MyOSCClient());
 }
 
 class MyOSCClient extends StatefulWidget {
   @override
-  State<StatefulWidget> createState() => new MyOSCClientState();
+  State<StatefulWidget> createState() => MyOSCClientState();
 }
 
 class MyOSCClientState extends State<MyOSCClient> {
   int _tabIndex = 0;
-  final tabTextStyleNormal = new TextStyle(color: const Color(0xff969696));
-  final tabTextStyleSelected = new TextStyle(color: const Color(0xff63ca6c));
+  final tabTextStyleNormal = TextStyle(color: const Color(0xff969696));
+  final tabTextStyleSelected = TextStyle(color: const Color(0xff63ca6c));
 
   var tabImages;
   var _body;
   var appBarTitles = ['资讯', '动弹', '发现', '我的'];
 
   Image getTabImage(path) {
-    return new Image.asset(path, width: 20.0, height: 20.0);
+    return Image.asset(path, width: 20.0, height: 20.0);
   }
 
   void initData() {
@@ -49,12 +49,12 @@ class MyOSCClientState extends State<MyOSCClient> {
         ]
       ];
     }
-    _body = new IndexedStack(
-      children: <Widget>[
-        new NewsListPage(),
-        new TweetsListPage(),
-        new DiscoveryPage(),
-        new MyInfoPage()
+    _body = IndexedStack(
+      children: [
+        NewsListPage(),
+        TweetsListPage(),
+        DiscoveryPage(),
+        MyInfoPage()
       ],
       index: _tabIndex,
     );
@@ -67,55 +67,45 @@ class MyOSCClientState extends State<MyOSCClient> {
     return tabTextStyleNormal;
   }
 
-  Image getTabIcon(int curIndex) {
+  Image? getTabIcon(int curIndex) {
     if (curIndex == _tabIndex) {
       return tabImages[curIndex][1];
     }
     return tabImages[curIndex][0];
   }
 
-  Text getTabTitle(int curIndex) {
-    return new Text(appBarTitles[curIndex], style: getTabTextStyle(curIndex));
+  String getTabTitle(int curIndex) {
+    return appBarTitles[
+        curIndex]; //Text(appBarTitles[curIndex], style: getTabTextStyle(curIndex));
   }
 
   @override
   Widget build(BuildContext context) {
     initData();
-    return new MaterialApp(
-      theme: new ThemeData(
-          primaryColor: const Color(0xFF63CA6C)
-      ),
-      home: new Scaffold(
-        appBar: new AppBar(
-          title: new Text(appBarTitles[_tabIndex], style: new TextStyle(color: Colors.white)),
-          iconTheme: new IconThemeData(color: Colors.white)
-        ),
+    return MaterialApp(
+      theme: ThemeData(primaryColor: const Color(0xFF63CA6C)),
+      home: Scaffold(
+        appBar: AppBar(
+            title: Text(appBarTitles[_tabIndex],
+                style: TextStyle(color: Colors.white)),
+            iconTheme: IconThemeData(color: Colors.white)),
         body: _body,
-        bottomNavigationBar: new CupertinoTabBar(
+        bottomNavigationBar: CupertinoTabBar(
           items: <BottomNavigationBarItem>[
-            new BottomNavigationBarItem(
-                icon: getTabIcon(0),
-                title: getTabTitle(0)),
-            new BottomNavigationBarItem(
-                icon: getTabIcon(1),
-                title: getTabTitle(1)),
-            new BottomNavigationBarItem(
-                icon: getTabIcon(2),
-                title: getTabTitle(2)),
-            new BottomNavigationBarItem(
-                icon: getTabIcon(3),
-                title: getTabTitle(3)),
+            BottomNavigationBarItem(icon: getTabIcon(0)!, label: getTabTitle(0)),
+            BottomNavigationBarItem(icon: getTabIcon(1)!, label: getTabTitle(1)),
+            BottomNavigationBarItem(icon: getTabIcon(2)!, label: getTabTitle(2)),
+            BottomNavigationBarItem(icon: getTabIcon(3)!, label: getTabTitle(3)),
           ],
           currentIndex: _tabIndex,
           onTap: (index) {
-            setState((){
+            setState(() {
               _tabIndex = index;
             });
           },
         ),
-        drawer: new MyDrawer(),
+        drawer: MyDrawer(),
       ),
     );
   }
 }
-

+ 0 - 0
lib/api/Api.dart → lib/model/api.dart


+ 1 - 1
lib/constants/Constants.dart → lib/model/constants.dart

@@ -10,6 +10,6 @@ class Constants {
 
   static final String END_LINE_TAG = "COMPLETE";
 
-  static EventBus eventBus = new EventBus();
+  static EventBus eventBus = EventBus();
   
 }

+ 7 - 7
lib/model/UserInfo.dart → lib/model/user_info.dart

@@ -2,13 +2,13 @@
 // 用户信息
 class UserInfo {
 
-  String gender;
-  String name;
-  String location;
-  num id;
-  String avatar;
-  String email;
-  String url;
+  String? gender;
+  String? name;
+  String? location;
+  num? id;
+  String? avatar;
+  String? email;
+  String? url;
 
   UserInfo({this.id, this.name, this.gender, this.avatar, this.email, this.location, this.url});
 

+ 0 - 153
lib/pages/AboutPage.dart

@@ -1,153 +0,0 @@
-import 'package:flutter/material.dart';
-import 'CommonWebPage.dart';
-
-// "关于"页面
-
-class AboutPage extends StatefulWidget {
-  @override
-  State<StatefulWidget> createState() {
-    return new AboutPageState();
-  }
-}
-
-class AboutPageState extends State<AboutPage> {
-  bool showImage = false;
-  TextStyle textStyle = new TextStyle(
-      color: Colors.blue,
-      decoration: new TextDecoration.combine([TextDecoration.underline]));
-  Widget authorLink, mayunLink, githubLink;
-  List<String> urls = new List();
-  List<String> titles = new List();
-
-  AboutPageState() {
-    titles.add("yubo's blog");
-    titles.add("码云");
-    titles.add("GitHub");
-    urls.add("https://yubo725.top");
-    urls.add("https://gitee.com/yubo725");
-    urls.add("https://github.com/yubo725");
-    authorLink = new GestureDetector(
-      child: new Container(
-        margin: const EdgeInsets.fromLTRB(0.0, 80.0, 0.0, 0.0),
-        child: new Row(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            new Text("作者:"),
-            new Text(
-              "yubo",
-              style: textStyle,
-            ),
-          ],
-        ),
-      ),
-      onTap: getLink(0),
-    );
-    mayunLink = new GestureDetector(
-      child: new Container(
-        margin: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
-        child: new Row(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            new Text("码云:"),
-            new Text(
-              "https://gitee.com/yubo725",
-              style: textStyle,
-            )
-          ],
-        ),
-      ),
-      onTap: getLink(1),
-    );
-    githubLink = new GestureDetector(
-      child: new Container(
-        margin: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
-        child: new Row(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            new Text("GitHub:"),
-            new Text(
-              "https://github.com/yubo725",
-              style: textStyle,
-            ),
-          ],
-        ),
-      ),
-      onTap: getLink(2),
-    );
-  }
-
-  getLink(index) {
-    String url = urls[index];
-    String title = titles[index];
-    return () {
-      Navigator.of(context).push(new MaterialPageRoute(builder: (ctx) {
-        return new CommonWebPage(title: title, url: url);
-      }));
-    };
-  }
-
-  Widget getImageOrBtn() {
-    if (!showImage) {
-      return new Container(
-        child: new Center(
-          child: new InkWell(
-            child: new Container(
-              padding: const EdgeInsets.fromLTRB(15.0, 8.0, 15.0, 8.0),
-              child: new Text("不要点我"),
-              decoration: new BoxDecoration(
-                  border: new Border.all(color: Colors.black),
-                  borderRadius: new BorderRadius.all(new Radius.circular(5.0))),
-            ),
-            onTap: () {
-              setState(() {
-                showImage = true;
-              });
-            },
-          ),
-        ),
-      );
-    } else {
-      return new Image.asset(
-        './images/ic_hongshu.jpg',
-        width: 100.0,
-        height: 100.0,
-      );
-    }
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return new Scaffold(
-      appBar: new AppBar(
-        title: new Text("关于", style: new TextStyle(color: Colors.white)),
-        iconTheme: new IconThemeData(color: Colors.white),
-      ),
-      body: new Center(
-        child: new Column(
-          children: <Widget>[
-            new Container(
-              width: 1.0,
-              height: 100.0,
-              color: Colors.transparent,
-            ),
-            new Image.asset(
-              './images/ic_osc_logo.png',
-              width: 200.0,
-              height: 56.0,
-            ),
-            new Text("基于Google Flutter的开源中国客户端"),
-            authorLink,
-            mayunLink,
-            githubLink,
-            new Expanded(flex: 1, child: getImageOrBtn()),
-            new Container(
-                margin: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 15.0),
-                child: new Text(
-                  "本项目仅供学习使用,与开源中国官方无关",
-                  style: new TextStyle(fontSize: 12.0),
-                ))
-          ],
-        ),
-      ));
-  }
-}

+ 15 - 15
lib/pages/CommonWebPage.dart

@@ -4,21 +4,21 @@ import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
 
 //公共的WebView页面,需要标题和URL参数
 class CommonWebPage extends StatefulWidget {
-  String title;
-  String url;
+  String? title;
+  String? url;
 
-  CommonWebPage({Key key, this.title, this.url}) : super(key: key);
+  CommonWebPage({Key? key, this.title, this.url}) : super(key: key);
 
   @override
   State<StatefulWidget> createState() {
-    return new CommonWebPageState();
+    return CommonWebPageState();
   }
 }
 
 class CommonWebPageState extends State<CommonWebPage> {
   bool loading = true;
 
-  final flutterWebViewPlugin = new FlutterWebviewPlugin();
+  final flutterWebViewPlugin = FlutterWebviewPlugin();
 
   @override
   void initState() {
@@ -46,22 +46,22 @@ class CommonWebPageState extends State<CommonWebPage> {
   @override
   Widget build(BuildContext context) {
     List<Widget> titleContent = [];
-    titleContent.add(new Text(
-      widget.title,
-      style: new TextStyle(color: Colors.white),
+    titleContent.add(Text(
+      widget.title!,
+      style: TextStyle(color: Colors.white),
     ));
     if (loading) {
-      titleContent.add(new CupertinoActivityIndicator());
+      titleContent.add(CupertinoActivityIndicator());
     }
-    titleContent.add(new Container(width: 50.0));
-    return new WebviewScaffold(
-      url: widget.url,
-      appBar: new AppBar(
-        title: new Row(
+    titleContent.add(Container(width: 50.0));
+    return WebviewScaffold(
+      url: widget.url!,
+      appBar: AppBar(
+        title: Row(
           mainAxisAlignment: MainAxisAlignment.center,
           children: titleContent,
         ),
-        iconTheme: new IconThemeData(color: Colors.white),
+        iconTheme: IconThemeData(color: Colors.white),
       ),
       withZoom: true,
       withLocalStorage: true,

+ 58 - 57
lib/pages/DiscoveryPage.dart

@@ -1,11 +1,10 @@
 import 'package:flutter/material.dart';
 import 'dart:async';
-import 'OfflineActivityPage.dart';
+import 'offline_activity_page.dart';
 import 'CommonWebPage.dart';
 import 'package:barcode_scan/barcode_scan.dart';
 
 class DiscoveryPage extends StatelessWidget {
-
   static const String TAG_START = "startDivider";
   static const String TAG_END = "endDivider";
   static const String TAG_CENTER = "centerDivider";
@@ -23,11 +22,13 @@ class DiscoveryPage extends StatelessWidget {
     "images/ic_discover_nearby.png",
     "images/ic_discover_pos.png",
   ];
-  final titles = [
-    "开源软件", "码云推荐", "代码片段", "扫一扫", "摇一摇", "码云封面人物", "线下活动"
-  ];
-  final rightArrowIcon = new Image.asset('images/ic_arrow_right.png', width: ARROW_ICON_WIDTH, height: ARROW_ICON_WIDTH,);
-  final titleTextStyle = new TextStyle(fontSize: 16.0);
+  final titles = ["开源软件", "码云推荐", "代码片段", "扫一扫", "摇一摇", "码云封面人物", "线下活动"];
+  final rightArrowIcon = Image.asset(
+    'images/ic_arrow_right.png',
+    width: ARROW_ICON_WIDTH,
+    height: ARROW_ICON_WIDTH,
+  );
+  final titleTextStyle = TextStyle(fontSize: 16.0);
   List listData = [];
 
   DiscoveryPage() {
@@ -37,7 +38,7 @@ class DiscoveryPage extends StatelessWidget {
   initData() {
     listData.add(TAG_START);
     for (int i = 0; i < 3; i++) {
-      listData.add(new ListItem(title: titles[i], icon: imagePaths[i]));
+      listData.add(ListItem(title: titles[i], icon: imagePaths[i]));
       if (i == 2) {
         listData.add(TAG_END);
       } else {
@@ -47,7 +48,7 @@ class DiscoveryPage extends StatelessWidget {
     listData.add(TAG_BLANK);
     listData.add(TAG_START);
     for (int i = 3; i < 5; i++) {
-      listData.add(new ListItem(title: titles[i], icon: imagePaths[i]));
+      listData.add(ListItem(title: titles[i], icon: imagePaths[i]));
       if (i == 4) {
         listData.add(TAG_END);
       } else {
@@ -57,7 +58,7 @@ class DiscoveryPage extends StatelessWidget {
     listData.add(TAG_BLANK);
     listData.add(TAG_START);
     for (int i = 5; i < 7; i++) {
-      listData.add(new ListItem(title: titles[i], icon: imagePaths[i]));
+      listData.add(ListItem(title: titles[i], icon: imagePaths[i]));
       if (i == 6) {
         listData.add(TAG_END);
       } else {
@@ -67,9 +68,10 @@ class DiscoveryPage extends StatelessWidget {
   }
 
   Widget getIconImage(path) {
-    return new Padding(
+    return Padding(
       padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
-      child: new Image.asset(path, width: IMAGE_ICON_WIDTH, height: IMAGE_ICON_WIDTH),
+      child:
+          Image.asset(path, width: IMAGE_ICON_WIDTH, height: IMAGE_ICON_WIDTH),
     );
   }
 
@@ -78,37 +80,45 @@ class DiscoveryPage extends StatelessWidget {
     if (item is String) {
       switch (item) {
         case TAG_START:
-          return new Divider(height: 1.0,);
+          return Divider(
+            height: 1.0,
+          );
           break;
         case TAG_END:
-          return new Divider(height: 1.0,);
+          return Divider(
+            height: 1.0,
+          );
           break;
         case TAG_CENTER:
-          return new Padding(
+          return Padding(
             padding: const EdgeInsets.fromLTRB(50.0, 0.0, 0.0, 0.0),
-            child: new Divider(height: 1.0,),
+            child: Divider(
+              height: 1.0,
+            ),
           );
           break;
         case TAG_BLANK:
-          return new Container(
+          return Container(
             height: 20.0,
           );
           break;
       }
     } else if (item is ListItem) {
-      var listItemContent =  new Padding(
+      var listItemContent = Padding(
         padding: const EdgeInsets.fromLTRB(10.0, 15.0, 10.0, 15.0),
-        child: new Row(
-          children: <Widget>[
+        child: Row(
+          children: [
             getIconImage(item.icon),
-            new Expanded(
-                child: new Text(item.title, style: titleTextStyle,)
-            ),
+            Expanded(
+                child: Text(
+              item.title!,
+              style: titleTextStyle,
+            )),
             rightArrowIcon
           ],
         ),
       );
-      return new InkWell(
+      return InkWell(
         onTap: () {
           handleListItemClick(ctx, item);
         },
@@ -118,45 +128,37 @@ class DiscoveryPage extends StatelessWidget {
   }
 
   void handleListItemClick(BuildContext ctx, ListItem item) {
-    String title = item.title;
+    String? title = item.title;
     if (title == "扫一扫") {
       scan();
     } else if (title == "线下活动") {
-      Navigator.of(ctx).push(new MaterialPageRoute(
-        builder: (context) {
-          return new OfflineActivityPage();
-        }
-      ));
+      Navigator.of(ctx).push(MaterialPageRoute(builder: (context) {
+        return OfflineActivityPage();
+      }));
     } else if (title == "码云推荐") {
-      Navigator.of(ctx).push(new MaterialPageRoute(
-          builder: (context) {
-            return new CommonWebPage(title: "码云推荐", url: "https://m.gitee.com/explore");
-          }
-      ));
+      Navigator.of(ctx).push(MaterialPageRoute(builder: (context) {
+        return CommonWebPage(title: "码云推荐", url: "https://m.gitee.com/explore");
+      }));
     } else if (title == "代码片段") {
-      Navigator.of(ctx).push(new MaterialPageRoute(
-          builder: (context) {
-            return new CommonWebPage(title: "代码片段", url: "https://m.gitee.com/gists");
-          }
-      ));
+      Navigator.of(ctx).push(MaterialPageRoute(builder: (context) {
+        return CommonWebPage(title: "代码片段", url: "https://m.gitee.com/gists");
+      }));
     } else if (title == "开源软件") {
-      Navigator.of(ctx).push(new MaterialPageRoute(
-          builder: (context) {
-            return new CommonWebPage(title: "开源软件", url: "https://m.gitee.com/explore");
-          }
-      ));
+      Navigator.of(ctx).push(MaterialPageRoute(builder: (context) {
+        return CommonWebPage(title: "开源软件", url: "https://m.gitee.com/explore");
+      }));
     } else if (title == "码云封面人物") {
-      Navigator.of(ctx).push(new MaterialPageRoute(
-          builder: (context) {
-            return new CommonWebPage(title: "码云封面人物", url: "https://m.gitee.com/gitee-stars/");
-          }
-      ));
+      Navigator.of(ctx).push(MaterialPageRoute(builder: (context) {
+        return CommonWebPage(
+            title: "码云封面人物", url: "https://m.gitee.com/gitee-stars/");
+      }));
     }
   }
 
   Future scan() async {
     try {
-      String barcode = await BarcodeScanner.scan();
+      ScanResult scanResult = await BarcodeScanner.scan();
+     String barcode = scanResult.rawContent.toString();
       print(barcode);
     } on Exception catch (e) {
       print(e);
@@ -165,19 +167,18 @@ class DiscoveryPage extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return new Padding(
+    return Padding(
       padding: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
-      child: new ListView.builder(
+      child: ListView.builder(
         itemCount: listData.length,
         itemBuilder: (context, i) => renderRow(context, i),
       ),
     );
   }
-
 }
 
 class ListItem {
-  String icon;
-  String title;
+  String? icon;
+  String? title;
   ListItem({this.icon, this.title});
-}
+}

+ 63 - 62
lib/pages/NewsListPage.dart

@@ -1,17 +1,18 @@
 import 'dart:async';
 import 'package:flutter/material.dart';
-import '../util/NetUtils.dart';
-import '../api/Api.dart';
+import 'package:flutter_osc/model/api.dart';
 import 'dart:convert';
-import '../constants/Constants.dart';
-import '../widgets/SlideView.dart';
-import '../pages/NewsDetailPage.dart';
-import '../widgets/CommonEndLine.dart';
+
+import 'package:flutter_osc/model/constants.dart';
+import 'package:flutter_osc/pages/news_detail_page.dart';
+import 'package:flutter_osc/util/NetUtils.dart';
+import 'package:flutter_osc/widgets/CommonEndLine.dart';
+import 'package:flutter_osc/widgets/SlideView.dart';
 
 class NewsListPage extends StatefulWidget {
   @override
   State<StatefulWidget> createState() {
-    return new NewsListPageState();
+    return NewsListPageState();
   }
 }
 
@@ -19,10 +20,10 @@ class NewsListPageState extends State<NewsListPage> {
   var listData;
   var slideData;
   var curPage = 1;
-  var listTotalSize = 0;
-  ScrollController _controller = new ScrollController();
-  TextStyle titleTextStyle = new TextStyle(fontSize: 15.0);
-  TextStyle subtitleStyle = new TextStyle(color: const Color(0xFFB5BDC0), fontSize: 12.0);
+  int? listTotalSize = 0;
+  ScrollController _controller = ScrollController();
+  TextStyle titleTextStyle = TextStyle(fontSize: 15.0);
+  TextStyle subtitleStyle = TextStyle(color: const Color(0xFFB5BDC0), fontSize: 12.0);
 
   NewsListPageState() {
     _controller.addListener(() {
@@ -52,16 +53,16 @@ class NewsListPageState extends State<NewsListPage> {
   @override
   Widget build(BuildContext context) {
     if (listData == null) {
-      return new Center(
-        child: new CircularProgressIndicator(),
+      return Center(
+        child: CircularProgressIndicator(),
       );
     } else {
-      Widget listView = new ListView.builder(
+      Widget listView = ListView.builder(
         itemCount: listData.length * 2,
         itemBuilder: (context, i) => renderRow(i),
         controller: _controller,
       );
-      return new RefreshIndicator(child: listView, onRefresh: _pullToRefresh);
+      return RefreshIndicator(child: listView, onRefresh: _pullToRefresh);
     }
   }
 
@@ -82,10 +83,10 @@ class NewsListPageState extends State<NewsListPage> {
               listData = _listData;
               slideData = _slideData;
             } else {
-              List list1 = new List();
+              List list1 = [];
               list1.addAll(listData);
               list1.addAll(_listData);
-              if (list1.length >= listTotalSize) {
+              if (list1.length >= listTotalSize!) {
                 list1.add(Constants.END_LINE_TAG);
               }
               listData = list1;
@@ -100,106 +101,106 @@ class NewsListPageState extends State<NewsListPage> {
 
   Widget renderRow(i) {
     if (i == 0) {
-      return new Container(
+      return Container(
         height: 180.0,
-        child: new SlideView(slideData),
+        child: SlideView(slideData),
       );
     }
     i -= 1;
     if (i.isOdd) {
-      return new Divider(height: 1.0);
+      return Divider(height: 1.0);
     }
     i = i ~/ 2;
     var itemData = listData[i];
     if (itemData is String && itemData == Constants.END_LINE_TAG) {
-      return new CommonEndLine();
+      return CommonEndLine();
     }
-    var titleRow = new Row(
-      children: <Widget>[
-        new Expanded(
-          child: new Text(itemData['title'], style: titleTextStyle),
+    var titleRow = Row(
+      children: [
+        Expanded(
+          child: Text(itemData['title'], style: titleTextStyle),
         )
       ],
     );
-    var timeRow = new Row(
-      children: <Widget>[
-        new Container(
+    var timeRow = Row(
+      children: [
+        Container(
           width: 20.0,
           height: 20.0,
-          decoration: new BoxDecoration(
+          decoration: BoxDecoration(
             shape: BoxShape.circle,
             color: const Color(0xFFECECEC),
-            image: new DecorationImage(
-                image: new NetworkImage(itemData['authorImg']), fit: BoxFit.cover),
-            border: new Border.all(
+            image: DecorationImage(
+                image: NetworkImage(itemData['authorImg']), fit: BoxFit.cover),
+            border: Border.all(
               color: const Color(0xFFECECEC),
               width: 2.0,
             ),
           ),
         ),
-        new Padding(
+        Padding(
           padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),
-          child: new Text(
+          child: Text(
             itemData['timeStr'],
             style: subtitleStyle,
           ),
         ),
-        new Expanded(
+        Expanded(
           flex: 1,
-          child: new Row(
+          child: Row(
             mainAxisAlignment: MainAxisAlignment.end,
-            children: <Widget>[
-              new Text("${itemData['commCount']}", style: subtitleStyle),
-              new Image.asset('./images/ic_comment.png', width: 16.0, height: 16.0),
+            children: [
+              Text("${itemData['commCount']}", style: subtitleStyle),
+              Image.asset('./images/ic_comment.png', width: 16.0, height: 16.0),
             ],
           ),
         )
       ],
     );
     var thumbImgUrl = itemData['thumb'];
-    var thumbImg = new Container(
+    var thumbImg = Container(
       margin: const EdgeInsets.all(10.0),
       width: 60.0,
       height: 60.0,
-      decoration: new BoxDecoration(
+      decoration: BoxDecoration(
         shape: BoxShape.circle,
         color: const Color(0xFFECECEC),
-        image: new DecorationImage(
-            image: new ExactAssetImage('./images/ic_img_default.jpg'),
+        image: DecorationImage(
+            image: ExactAssetImage('./images/ic_img_default.jpg'),
             fit: BoxFit.cover),
-        border: new Border.all(
+        border: Border.all(
           color: const Color(0xFFECECEC),
           width: 2.0,
         ),
       ),
     );
     if (thumbImgUrl != null && thumbImgUrl.length > 0) {
-      thumbImg = new Container(
+      thumbImg = Container(
         margin: const EdgeInsets.all(10.0),
         width: 60.0,
         height: 60.0,
-        decoration: new BoxDecoration(
+        decoration: BoxDecoration(
           shape: BoxShape.circle,
           color: const Color(0xFFECECEC),
-          image: new DecorationImage(
-              image: new NetworkImage(thumbImgUrl), fit: BoxFit.cover),
-          border: new Border.all(
+          image: DecorationImage(
+              image: NetworkImage(thumbImgUrl), fit: BoxFit.cover),
+          border: Border.all(
             color: const Color(0xFFECECEC),
             width: 2.0,
           ),
         ),
       );
     }
-    var row = new Row(
-      children: <Widget>[
-        new Expanded(
+    var row = Row(
+      children: [
+        Expanded(
           flex: 1,
-          child: new Padding(
+          child: Padding(
             padding: const EdgeInsets.all(10.0),
-            child: new Column(
-              children: <Widget>[
+            child: Column(
+              children: [
                 titleRow,
-                new Padding(
+                Padding(
                   padding: const EdgeInsets.fromLTRB(0.0, 8.0, 0.0, 0.0),
                   child: timeRow,
                 )
@@ -207,24 +208,24 @@ class NewsListPageState extends State<NewsListPage> {
             ),
           ),
         ),
-        new Padding(
+        Padding(
           padding: const EdgeInsets.all(6.0),
-          child: new Container(
+          child: Container(
             width: 100.0,
             height: 80.0,
             color: const Color(0xFFECECEC),
-            child: new Center(
+            child: Center(
               child: thumbImg,
             ),
           ),
         )
       ],
     );
-    return new InkWell(
+    return InkWell(
       child: row,
       onTap: () {
-        Navigator.of(context).push(new MaterialPageRoute(
-          builder: (ctx) => new NewsDetailPage(id: itemData['detailUrl'])
+        Navigator.of(context).push(MaterialPageRoute(
+          builder: (ctx) => NewsDetailPage(id: itemData['detailUrl'])
         ));
       },
     );

+ 101 - 97
lib/pages/PublishTweetPage.dart

@@ -3,54 +3,52 @@ import 'dart:convert';
 import 'dart:io';
 import 'package:async/async.dart';
 import 'package:flutter/material.dart';
-import 'package:http/http.dart';
-import '../api/Api.dart';
+import 'package:flutter_osc/model/api.dart';
+import 'package:flutter_osc/util/DataUtils.dart';
 import 'package:http/http.dart' as http;
-import '../util/DataUtils.dart';
 import 'package:image_picker/image_picker.dart';
 
 class PublishTweetPage extends StatefulWidget {
   @override
   State<StatefulWidget> createState() {
-    return new PublishTweetPageState();
+    return PublishTweetPageState();
   }
 }
 
 class PublishTweetPageState extends State<PublishTweetPage> {
-
-  TextEditingController _controller = new TextEditingController();
-  List<File> fileList = new List();
-  Future<File> _imageFile;
+  TextEditingController _controller = TextEditingController();
+  List<File> fileList = [];
+  Future<XFile?>? _imageFile;
   bool isLoading = false;
   String msg = "";
 
   Widget getBody() {
-    var textField = new TextField(
-      decoration: new InputDecoration(
-        hintText: "说点什么吧~",
-        hintStyle: new TextStyle(
-          color: const Color(0xFF808080)
-        ),
-        border: new OutlineInputBorder(
-          borderRadius: const BorderRadius.all(const Radius.circular(10.0))
-        )
-      ),
+    var textField = TextField(
+      decoration: InputDecoration(
+          hintText: "说点什么吧~",
+          hintStyle: TextStyle(color: const Color(0xFF808080)),
+          border: OutlineInputBorder(
+              borderRadius:
+                  const BorderRadius.all(const Radius.circular(10.0)))),
       maxLines: 6,
       maxLength: 150,
       controller: _controller,
     );
-    var gridView = new Builder(
+    var gridView = Builder(
       builder: (ctx) {
-        return new GridView.count(
+        return GridView.count(
           crossAxisCount: 4,
-          children: new List.generate(fileList.length + 1, (index) {
+          children: List.generate(fileList.length + 1, (index) {
             var content;
             if (index == 0) {
               // 添加图片按钮
-              var addCell = new Center(
-                  child: new Image.asset('./images/ic_add_pics.png', width: 80.0, height: 80.0,)
-              );
-              content = new GestureDetector(
+              var addCell = Center(
+                  child: Image.asset(
+                './images/ic_add_pics.png',
+                width: 80.0,
+                height: 80.0,
+              ));
+              content = GestureDetector(
                 onTap: () {
                   // 添加图片
                   pickImage(ctx);
@@ -59,11 +57,15 @@ class PublishTweetPageState extends State<PublishTweetPage> {
               );
             } else {
               // 被选中的图片
-              content = new Center(
-                  child: new Image.file(fileList[index - 1], width: 80.0, height: 80.0, fit: BoxFit.cover,)
-              );
+              content = Center(
+                  child: Image.file(
+                fileList[index - 1],
+                width: 80.0,
+                height: 80.0,
+                fit: BoxFit.cover,
+              ));
             }
-            return new Container(
+            return Container(
               margin: const EdgeInsets.all(2.0),
               width: 80.0,
               height: 80.0,
@@ -75,32 +77,33 @@ class PublishTweetPageState extends State<PublishTweetPage> {
       },
     );
     var children = [
-      new Text("提示:由于OSC的openapi限制,发布动弹的接口只支持上传一张图片,本项目可添加最多9张图片,但OSC只会接收最后一张图片。", style: new TextStyle(fontSize: 12.0),),
+      Text(
+        "提示:由于OSC的openapi限制,发布动弹的接口只支持上传一张图片,本项目可添加最多9张图片,但OSC只会接收最后一张图片。",
+        style: TextStyle(fontSize: 12.0),
+      ),
       textField,
-      new Container(
+      Container(
           margin: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
           height: 200.0,
-          child: gridView
-      )
+          child: gridView)
     ];
     if (isLoading) {
-      children.add(new Container(
+      children.add(Container(
         margin: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
-        child: new Center(
-          child: new CircularProgressIndicator(),
+        child: Center(
+          child: CircularProgressIndicator(),
         ),
       ));
     } else {
-      children.add(new Container(
-        margin: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
-        child: new Center(
-          child: new Text(msg),
-        )
-      ));
+      children.add(Container(
+          margin: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
+          child: Center(
+            child: Text(msg),
+          )));
     }
-    return new Container(
+    return Container(
       padding: const EdgeInsets.all(5.0),
-      child: new Column(
+      child: Column(
         children: children,
       ),
     );
@@ -111,8 +114,8 @@ class PublishTweetPageState extends State<PublishTweetPage> {
     // 如果已添加了9张图片,则提示不允许添加更多
     num size = fileList.length;
     if (size >= 9) {
-      Scaffold.of(ctx).showSnackBar(new SnackBar(
-        content: new Text("最多只能添加9张图片!"),
+      Scaffold.of(ctx).showSnackBar(SnackBar(
+        content: Text("最多只能添加9张图片!"),
       ));
       return;
     }
@@ -120,34 +123,33 @@ class PublishTweetPageState extends State<PublishTweetPage> {
   }
 
   Widget _bottomSheetBuilder(BuildContext context) {
-    return new Container(
-      height: 182.0,
-      child: new Padding(
-        padding: const EdgeInsets.fromLTRB(0.0, 30.0, 0.0, 30.0),
-        child: new Column(
-          children: <Widget>[
-            _renderBottomMenuItem("相机拍照", ImageSource.camera),
-            new Divider(height: 2.0,),
-            _renderBottomMenuItem("图库选择照片", ImageSource.gallery)
-          ],
-        ),
-      )
-    );
+    return Container(
+        height: 182.0,
+        child: Padding(
+          padding: const EdgeInsets.fromLTRB(0.0, 30.0, 0.0, 30.0),
+          child: Column(
+            children: [
+              _renderBottomMenuItem("相机拍照", ImageSource.camera),
+              Divider(
+                height: 2.0,
+              ),
+              _renderBottomMenuItem("图库选择照片", ImageSource.gallery)
+            ],
+          ),
+        ));
   }
 
   _renderBottomMenuItem(title, ImageSource source) {
-    var item = new Container(
+    var item = Container(
       height: 60.0,
-      child: new Center(
-        child: new Text(title)
-      ),
+      child: Center(child: Text(title)),
     );
-    return new InkWell(
+    return InkWell(
       child: item,
       onTap: () {
         Navigator.of(context).pop();
         setState(() {
-          _imageFile = ImagePicker.pickImage(source: source);
+          _imageFile = ImagePicker().pickImage(source: source);
         });
       },
     );
@@ -155,31 +157,30 @@ class PublishTweetPageState extends State<PublishTweetPage> {
 
   sendTweet(ctx, token) async {
     if (token == null) {
-      Scaffold.of(ctx).showSnackBar(new SnackBar(
-        content: new Text("未登录!"),
+      Scaffold.of(ctx).showSnackBar(SnackBar(
+        content: Text("未登录!"),
       ));
       return;
     }
     String content = _controller.text;
     if (content == null || content.length == 0 || content.trim().length == 0) {
-      Scaffold.of(ctx).showSnackBar(new SnackBar(
-        content: new Text("请输入动弹内容!"),
+      Scaffold.of(ctx).showSnackBar(SnackBar(
+        content: Text("请输入动弹内容!"),
       ));
     }
     try {
-      Map<String, String> params = new Map();
+      Map<String, String> params = Map();
       params['msg'] = content;
       params['access_token'] = token;
-      var request = new MultipartRequest('POST', Uri.parse(Api.PUB_TWEET));
+      var request = http.MultipartRequest('POST', Uri.parse(Api.PUB_TWEET));
       request.fields.addAll(params);
       if (fileList != null && fileList.length > 0) {
         for (File f in fileList) {
-          var stream = new http.ByteStream(
-              DelegatingStream.typed(f.openRead()));
+          var stream = http.ByteStream(DelegatingStream.typed(f.openRead()));
           var length = await f.length();
           var filename = f.path.substring(f.path.lastIndexOf("/") + 1);
-          request.files.add(new http.MultipartFile(
-              'img', stream, length, filename: filename));
+          request.files.add(
+              http.MultipartFile('img', stream, length, filename: filename));
         }
       }
       setState(() {
@@ -216,35 +217,38 @@ class PublishTweetPageState extends State<PublishTweetPage> {
 
   @override
   Widget build(BuildContext context) {
-    return new Scaffold(
-      appBar: new AppBar(
-        title: new Text("发布动弹", style: new TextStyle(color: Colors.white)),
-        iconTheme: new IconThemeData(color: Colors.white),
+    return Scaffold(
+      appBar: AppBar(
+        title: Text("发布动弹", style: TextStyle(color: Colors.white)),
+        iconTheme: IconThemeData(color: Colors.white),
         actions: <Widget>[
-          new Builder(
+          Builder(
             builder: (ctx) {
-              return new IconButton(icon: new Icon(Icons.send), onPressed: () {
-                // 发送动弹
-                DataUtils.isLogin().then((isLogin) {
-                  if (isLogin) {
-                    return DataUtils.getAccessToken();
-                  } else {
-                    return null;
-                  }
-                }).then((token) {
-                  sendTweet(ctx, token);
-                });
-              });
+              return IconButton(
+                  icon: Icon(Icons.send),
+                  onPressed: () {
+                    // 发送动弹
+                    DataUtils.isLogin().then((isLogin) {
+                      if (isLogin) {
+                        return DataUtils.getAccessToken();
+                      } else {
+                        return null;
+                      }
+                    }).then((token) {
+                      sendTweet(ctx, token);
+                    });
+                  });
             },
           )
         ],
       ),
-      body: new FutureBuilder(
+      body: FutureBuilder(
         future: _imageFile,
-        builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
+        builder: (BuildContext context, AsyncSnapshot<XFile?> snapshot) {
           if (snapshot.connectionState == ConnectionState.done &&
-              snapshot.data != null && _imageFile != null) {
-            fileList.add(snapshot.data);
+              snapshot.data != null &&
+              _imageFile != null) {
+            fileList.add(File(snapshot.data!.path));
             _imageFile = null;
           }
           return getBody();
@@ -252,4 +256,4 @@ class PublishTweetPageState extends State<PublishTweetPage> {
       ),
     );
   }
-}
+}

+ 14 - 15
lib/pages/TestPage.dart

@@ -1,36 +1,35 @@
 import 'package:flutter/material.dart';
-import 'package:flutter/cupertino.dart';
 
 class TestPage extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
-    return new MaterialApp(
+    return MaterialApp(
       title: "Test",
-      home: new Scaffold(
-        appBar: new AppBar(
-          title: new Text("Test"),
+      home: Scaffold(
+        appBar: AppBar(
+          title: Text("Test"),
         ),
-        body: new Center(
-          child: new Column(
+        body: Center(
+          child: Column(
             mainAxisAlignment: MainAxisAlignment.center,
-            children: <Widget>[
-              new Text("hello"),
-              new Text("world")
+            children: [
+              Text("hello"),
+              Text("world")
             ],
           ),
         ),
-//        body: new Container(
+//        body: Container(
 //          margin: const EdgeInsets.all(10.0),
 //          width: 80.0,
 //          height: 80.0,
-//          decoration: new BoxDecoration(
+//          decoration: BoxDecoration(
 //            shape: BoxShape.circle,
 //            color: Colors.blue,
-//            image: new DecorationImage(
-//              image: new ExactAssetImage('./images/ic_test.png'),
+//            image: DecorationImage(
+//              image: ExactAssetImage('./images/ic_test.png'),
 //              fit: BoxFit.cover
 //            ),
-//            border: new Border.all(
+//            border: Border.all(
 //              color: Colors.white,
 //              width: 2.0,
 //            ),

+ 124 - 122
lib/pages/TweetDetailPage.dart

@@ -1,43 +1,45 @@
 import 'package:flutter/material.dart';
-import '../util/NetUtils.dart';
-import '../api/Api.dart';
-import '../constants/Constants.dart';
+import 'package:flutter_osc/model/api.dart';
+import 'package:flutter_osc/model/constants.dart';
 import 'dart:convert';
-import '../widgets/CommonEndLine.dart';
-import '../util/DataUtils.dart';
+
+import 'package:flutter_osc/util/DataUtils.dart';
+import 'package:flutter_osc/util/NetUtils.dart';
+import 'package:flutter_osc/widgets/CommonEndLine.dart';
+
 
 // 动弹详情
 
 class TweetDetailPage extends StatefulWidget {
-  Map<String, dynamic> tweetData;
+  Map<String, dynamic>? tweetData;
 
-  TweetDetailPage({Key key, this.tweetData}):super(key: key);
+  TweetDetailPage({Key? key, this.tweetData}):super(key: key);
 
   @override
   State<StatefulWidget> createState() {
-    return new TweetDetailPageState(tweetData: tweetData);
+    return TweetDetailPageState(tweetData: tweetData);
   }
 }
 
 class TweetDetailPageState extends State<TweetDetailPage> {
 
-  Map<String, dynamic> tweetData;
-  List commentList;
-  RegExp regExp1 = new RegExp("</.*>");
-  RegExp regExp2 = new RegExp("<.*>");
-  TextStyle subtitleStyle = new TextStyle(
+  Map<String, dynamic>? tweetData;
+  List? commentList;
+  RegExp regExp1 = RegExp("</.*>");
+  RegExp regExp2 = RegExp("<.*>");
+  TextStyle subtitleStyle = TextStyle(
       fontSize: 12.0,
       color: const Color(0xFFB5BDC0)
   );
-  TextStyle contentStyle = new TextStyle(
+  TextStyle contentStyle = TextStyle(
       fontSize: 15.0,
       color: Colors.black
   );
   num curPage = 1;
-  ScrollController _controller = new ScrollController();
-  TextEditingController _inputController = new TextEditingController();
+  ScrollController _controller = ScrollController();
+  TextEditingController _inputController = TextEditingController();
 
-  TweetDetailPageState({Key key, this.tweetData});
+  TweetDetailPageState({Key? key, this.tweetData});
 
   // 获取动弹的回复
   getReply(bool isLoadMore) {
@@ -47,8 +49,8 @@ class TweetDetailPageState extends State<TweetDetailPage> {
           if (token == null || token.length == 0) {
             return;
           }
-          Map<String, String> params = new Map();
-          var id = this.tweetData['id'];
+          Map<String, String> params = Map();
+          var id = this.tweetData!['id'];
           params['id'] = '$id';
           params['catalog'] = '3';// 3是动弹评论
           params['access_token'] = token;
@@ -60,14 +62,14 @@ class TweetDetailPageState extends State<TweetDetailPage> {
               if (!isLoadMore) {
                 commentList = json.decode(data)['commentList'];
                 if (commentList == null) {
-                  commentList = new List();
+                  commentList = [];
                 }
               } else {
                 // 加载更多数据
-                List list = new List();
-                list.addAll(commentList);
+                List list = [];
+                list.addAll(commentList!);
                 list.addAll(json.decode(data)['commentList']);
-                if (list.length >= tweetData['commentCount']) {
+                if (list.length >= tweetData!['commentCount']) {
                   list.add(Constants.END_LINE_TAG);
                 }
                 commentList = list;
@@ -86,7 +88,7 @@ class TweetDetailPageState extends State<TweetDetailPage> {
     _controller.addListener(() {
       var max = _controller.position.maxScrollExtent;
       var pixels = _controller.position.pixels;
-      if (max == pixels && commentList.length < tweetData['commentCount']) {
+      if (max == pixels && commentList!.length < tweetData!['commentCount']) {
         // scroll to end, load next page
         curPage++;
         getReply(true);
@@ -96,20 +98,20 @@ class TweetDetailPageState extends State<TweetDetailPage> {
 
   @override
   Widget build(BuildContext context) {
-    var _body = commentList == null ? new Center(
-      child: new CircularProgressIndicator(),
-    ) : new ListView.builder(
-      itemCount: commentList.length == 0 ? 1 : commentList.length * 2,
+    var _body = commentList == null ? Center(
+      child: CircularProgressIndicator(),
+    ) : ListView.builder(
+      itemCount: commentList!.length == 0 ? 1 : commentList!.length * 2,
       itemBuilder: renderListItem,
       controller: _controller,
     );
-    return new Scaffold(
-      appBar: new AppBar(
-        title: new Text("动弹详情", style: new TextStyle(color: Colors.white)),
-        iconTheme: new IconThemeData(color: Colors.white),
+    return Scaffold(
+      appBar: AppBar(
+        title: Text("动弹详情", style: TextStyle(color: Colors.white)),
+        iconTheme: IconThemeData(color: Colors.white),
         actions: <Widget>[
-          new IconButton(
-            icon: new Icon(Icons.send),
+          IconButton(
+            icon: Icon(Icons.send),
             onPressed: () {
               // 回复楼主
               showReplyBottomView(context, true);
@@ -123,11 +125,11 @@ class TweetDetailPageState extends State<TweetDetailPage> {
 
   Widget renderListItem(BuildContext context, int i) {
     if (i == 0) {
-      return getTweetView(this.tweetData);
+      return getTweetView(this.tweetData!);
     }
     i -= 1;
     if (i.isOdd) {
-      return new Divider(height: 1.0,);
+      return Divider(height: 1.0,);
     }
     i ~/= 2;
     return _renderCommentRow(context, i);
@@ -135,43 +137,43 @@ class TweetDetailPageState extends State<TweetDetailPage> {
 
   // 渲染评论列表
   _renderCommentRow(context, i) {
-    var listItem = commentList[i];
+    var listItem = commentList![i];
     if (listItem is String && listItem == Constants.END_LINE_TAG) {
-      return new CommonEndLine();
+      return CommonEndLine();
     }
     String avatar = listItem['commentPortrait'];
     String author = listItem['commentAuthor'];
     String date = listItem['pubDate'];
     String content = listItem['content'];
     content = clearHtmlContent(content);
-    var row = new Row(
-      children: <Widget>[
-        new Padding(
+    var row = Row(
+      children: [
+        Padding(
           padding: const EdgeInsets.all(10.0),
-          child: new Image.network(avatar, width: 35.0, height: 35.0,)
+          child: Image.network(avatar, width: 35.0, height: 35.0,)
         ),
-        new Expanded(
-          child: new Container(
+        Expanded(
+          child: Container(
             margin: const EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 5.0),
-            child: new Column(
-              children: <Widget>[
-                new Row(
-                  children: <Widget>[
-                    new Expanded(
-                      child: new Text(author, style: new TextStyle(color: const Color(0xFF63CA6C)),),
+            child: Column(
+              children: [
+                Row(
+                  children: [
+                    Expanded(
+                      child: Text(author, style: TextStyle(color: const Color(0xFF63CA6C)),),
                     ),
-                    new Padding(
+                    Padding(
                         padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
-                        child: new Text(date, style: subtitleStyle,)
+                        child: Text(date, style: subtitleStyle,)
                     )
                   ],
                 ),
-                new Padding(
+                Padding(
                     padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
-                    child: new Row(
-                      children: <Widget>[
-                        new Expanded(
-                            child: new Text(content, style: contentStyle,)
+                    child: Row(
+                      children: [
+                        Expanded(
+                            child: Text(content, style: contentStyle,)
                         )
                       ],
                     )
@@ -182,9 +184,9 @@ class TweetDetailPageState extends State<TweetDetailPage> {
         )
       ],
     );
-    return new Builder(
+    return Builder(
       builder: (ctx) {
-        return new InkWell(
+        return InkWell(
           onTap: () {
             showReplyBottomView(ctx, false, data: listItem);
           },
@@ -198,8 +200,8 @@ class TweetDetailPageState extends State<TweetDetailPage> {
     String title;
     String authorId;
     if (isMainFloor) {
-      title = "@${tweetData['author']}";
-      authorId = "${tweetData['authorid']}";
+      title = "@${tweetData!['author']}";
+      authorId = "${tweetData!['authorid']}";
     } else {
       title = "@${data['commentAuthor']}";
       authorId = "${data['commentAuthorId']}";
@@ -208,26 +210,26 @@ class TweetDetailPageState extends State<TweetDetailPage> {
     showModalBottomSheet(
       context: ctx,
       builder: (sheetCtx) {
-        return new Container(
+        return Container(
           height: 230.0,
           padding: const EdgeInsets.all(20.0),
-          child: new Column(
-            children: <Widget>[
-              new Row(
-                children: <Widget>[
-                  new Text(isMainFloor ? "回复楼主" : "回复"),
-                  new Expanded(child: new Text(title, style: new TextStyle(color: const Color(0xFF63CA6C)),)),
-                  new InkWell(
-                    child: new Container(
+          child: Column(
+            children: [
+              Row(
+                children: [
+                  Text(isMainFloor ? "回复楼主" : "回复"),
+                  Expanded(child: Text(title, style: TextStyle(color: const Color(0xFF63CA6C)),)),
+                  InkWell(
+                    child: Container(
                       padding: const EdgeInsets.fromLTRB(10.0, 6.0, 10.0, 6.0),
-                      decoration: new BoxDecoration(
-                        border: new Border.all(
+                      decoration: BoxDecoration(
+                        border: Border.all(
                           color: const Color(0xFF63CA6C),
                           width: 1.0,
                         ),
-                        borderRadius: new BorderRadius.all(new Radius.circular(6.0))
+                        borderRadius: BorderRadius.all(Radius.circular(6.0))
                       ),
-                      child: new Text("发送", style: new TextStyle(color: const Color(0xFF63CA6C)),),
+                      child: Text("发送", style: TextStyle(color: const Color(0xFF63CA6C)),),
                     ),
                     onTap: () {
                       // 发送回复
@@ -236,18 +238,18 @@ class TweetDetailPageState extends State<TweetDetailPage> {
                   )
                 ],
               ),
-              new Container(
+              Container(
                 height: 10.0,
               ),
-              new TextField(
+              TextField(
                 maxLines: 5,
                 controller: _inputController,
-                decoration: new InputDecoration(
+                decoration: InputDecoration(
                   hintText: "说点啥~",
-                  hintStyle: new TextStyle(
+                  hintStyle: TextStyle(
                       color: const Color(0xFF808080)
                   ),
-                  border: new OutlineInputBorder(
+                  border: OutlineInputBorder(
                     borderRadius: const BorderRadius.all(const Radius.circular(10.0)),
                   )
                 ),
@@ -267,10 +269,10 @@ class TweetDetailPageState extends State<TweetDetailPage> {
       DataUtils.isLogin().then((isLogin) {
         if (isLogin) {
           DataUtils.getAccessToken().then((token) {
-            Map<String, String> params = new Map();
+            Map<String, String?> params = Map();
             params['access_token'] = token;
-            params['id'] = "${tweetData['id']}";
-            print("id: ${tweetData['id']}");
+            params['id'] = "${tweetData!['id']}";
+            print("id: ${tweetData!['id']}");
             params['catalog'] = "3";
             params['content'] = replyStr;
             params['authorid'] = "$authorId";
@@ -295,36 +297,36 @@ class TweetDetailPageState extends State<TweetDetailPage> {
   }
 
   Widget getTweetView(Map<String, dynamic> listItem) {
-    var authorRow = new Row(
-      children: <Widget>[
-        new Container(
+    var authorRow = Row(
+      children: [
+        Container(
           width: 35.0,
           height: 35.0,
-          decoration: new BoxDecoration(
+          decoration: BoxDecoration(
             shape: BoxShape.circle,
             color: Colors.blue,
-            image: new DecorationImage(
-                image: new NetworkImage(listItem['portrait']),
+            image: DecorationImage(
+                image: NetworkImage(listItem['portrait']),
                 fit: BoxFit.cover
             ),
-            border: new Border.all(
+            border: Border.all(
               color: Colors.white,
               width: 2.0,
             ),
           ),
         ),
-        new Padding(
+        Padding(
             padding: const EdgeInsets.fromLTRB(6.0, 0.0, 0.0, 0.0),
-            child: new Text(listItem['author'], style: new TextStyle(
+            child: Text(listItem['author'], style: TextStyle(
               fontSize: 16.0,
             ))
         ),
-        new Expanded(
-          child: new Row(
+        Expanded(
+          child: Row(
             mainAxisAlignment: MainAxisAlignment.end,
-            children: <Widget>[
-              new Text('${listItem['commentCount']}', style: subtitleStyle,),
-              new Image.asset('./images/ic_comment.png', width: 20.0, height: 20.0,)
+            children: [
+              Text('${listItem['commentCount']}', style: subtitleStyle,),
+              Image.asset('./images/ic_comment.png', width: 20.0, height: 20.0,)
             ],
           ),
         )
@@ -332,32 +334,32 @@ class TweetDetailPageState extends State<TweetDetailPage> {
     );
     var _body = listItem['body'];
     _body = clearHtmlContent(_body);
-    var contentRow = new Row(
-      children: <Widget>[
-        new Expanded(child: new Text(_body),)
+    var contentRow = Row(
+      children: [
+        Expanded(child: Text(_body),)
       ],
     );
-    var timeRow = new Row(
+    var timeRow = Row(
       mainAxisAlignment: MainAxisAlignment.start,
-      children: <Widget>[
-        new Text(listItem['pubDate'], style: subtitleStyle,)
+      children: [
+        Text(listItem['pubDate'], style: subtitleStyle,)
       ],
     );
     var columns = <Widget>[
-      new Padding(
+      Padding(
         padding: const EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 2.0),
         child: authorRow,
       ),
-      new Padding(
+      Padding(
         padding: const EdgeInsets.fromLTRB(52.0, 0.0, 10.0, 0.0),
         child: contentRow,
       ),
     ];
-    String imgSmall = listItem['imgSmall'];
+    String? imgSmall = listItem['imgSmall'];
     if (imgSmall != null && imgSmall.length > 0) {
       // 动弹中有图片
       List<String> list = imgSmall.split(",");
-      List<String> imgUrlList = new List<String>();
+      List<String> imgUrlList = <String>[];
       for (String s in list) {
         if (s.startsWith("http")) {
           imgUrlList.add(s);
@@ -368,59 +370,59 @@ class TweetDetailPageState extends State<TweetDetailPage> {
       List<Widget> imgList = [];
       List rows = [];
       num len = imgUrlList.length;
-      for (var row = 0; row < getRow(len); row++) {
+      for (var row = 0; row < getRow(len as int); row++) {
         List<Widget> rowArr = [];
         for (var col = 0; col < 3; col++) {
           num index = row * 3 + col;
           num screenWidth = MediaQuery.of(context).size.width;
           double cellWidth = (screenWidth - 100) / 3;
           if (index < len) {
-            rowArr.add(new Padding(
+            rowArr.add(Padding(
               padding: const EdgeInsets.all(2.0),
-              child: new Image.network(imgUrlList[index], width: cellWidth, height: cellWidth),
+              child: Image.network(imgUrlList[index as int], width: cellWidth, height: cellWidth),
             ));
           }
         }
         rows.add(rowArr);
       }
       for (var row in rows) {
-        imgList.add(new Row(
+        imgList.add(Row(
           children: row,
         ));
       }
-      columns.add(new Padding(
+      columns.add(Padding(
         padding: const EdgeInsets.fromLTRB(52.0, 5.0, 10.0, 0.0),
-        child: new Column(
+        child: Column(
           children: imgList,
         ),
       ));
     }
-    columns.add(new Padding(
+    columns.add(Padding(
       padding: const EdgeInsets.fromLTRB(52.0, 10.0, 10.0, 6.0),
       child: timeRow,
     ));
-    columns.add(new Divider(height: 5.0,));
-    columns.add(new Container(
+    columns.add(Divider(height: 5.0,));
+    columns.add(Container(
       margin: const EdgeInsets.fromLTRB(0.0, 6.0, 0.0, 0.0),
-      child: new Row(
-        children: <Widget>[
-          new Container(
+      child: Row(
+        children: [
+          Container(
             width: 4.0,
             height: 20.0,
             color: const Color(0xFF63CA6C),
           ),
-          new Expanded(
+          Expanded(
             flex: 1,
-            child: new Container(
+            child: Container(
               height: 20.0,
               color: const Color(0xFFECECEC),
-              child: new Text("评论列表", style: new TextStyle(color: const Color(0xFF63CA6C)),)
+              child: Text("评论列表", style: TextStyle(color: const Color(0xFF63CA6C)),)
             ),
           )
         ],
       ),
     ));
-    return new Column(
+    return Column(
       children: columns,
     );
   }

+ 121 - 122
lib/pages/TweetsListPage.dart

@@ -1,13 +1,12 @@
 import 'package:flutter/material.dart';
-import 'package:flutter_osc/constants/Constants.dart';
+import 'package:flutter_osc/model/constants.dart';
 import 'package:flutter_osc/events/LoginEvent.dart';
-import 'package:flutter_osc/events/LogoutEvent.dart';
 import 'package:flutter_osc/util/Utf8Utils.dart';
 import '../util/BlackListUtils.dart';
-import '../api/Api.dart';
+import '../model/api.dart';
 import '../util/NetUtils.dart';
 import '../pages/TweetDetailPage.dart';
-import 'LoginPage.dart';
+import 'login_page.dart';
 import 'dart:convert';
 import 'dart:async';
 import '../util/DataUtils.dart';
@@ -15,20 +14,20 @@ import '../util/DataUtils.dart';
 class TweetsListPage extends StatefulWidget {
   @override
   State<StatefulWidget> createState() {
-    return new TweetsListPageState();
+    return TweetsListPageState();
   }
 }
 
 class TweetsListPageState extends State<TweetsListPage> {
-  List hotTweetsList;
-  List normalTweetsList;
-  TextStyle authorTextStyle;
-  TextStyle subtitleStyle;
-  RegExp regExp1 = new RegExp("</.*>");
-  RegExp regExp2 = new RegExp("<.*>");
+  List? hotTweetsList;
+  List? normalTweetsList;
+  TextStyle? authorTextStyle;
+  TextStyle? subtitleStyle;
+  RegExp regExp1 = RegExp("</.*>");
+  RegExp regExp2 = RegExp("<.*>");
   num curPage = 1;
   bool loading = false;
-  ScrollController _controller;
+  ScrollController? _controller;
   bool isUserLogin = false;
 
   @override
@@ -39,12 +38,12 @@ class TweetsListPageState extends State<TweetsListPage> {
         this.isUserLogin = isLogin;
       });
     });
-    Constants.eventBus.on(LoginEvent).listen((event) {
+    Constants.eventBus.on().listen((event) {
       setState(() {
         this.isUserLogin = true;
       });
     });
-    Constants.eventBus.on(LogoutEvent).listen((event) {
+    Constants.eventBus.on().listen((event) {
       setState(() {
         this.isUserLogin = false;
       });
@@ -53,13 +52,13 @@ class TweetsListPageState extends State<TweetsListPage> {
 
   TweetsListPageState() {
     authorTextStyle =
-        new TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold);
+        TextStyle(fontSize: 15.0, fontWeight: FontWeight.bold);
     subtitleStyle =
-        new TextStyle(fontSize: 12.0, color: const Color(0xFFB5BDC0));
-    _controller = new ScrollController();
-    _controller.addListener(() {
-      var maxScroll = _controller.position.maxScrollExtent;
-      var pixels = _controller.position.pixels;
+        TextStyle(fontSize: 12.0, color: const Color(0xFFB5BDC0));
+    _controller = ScrollController();
+    _controller!.addListener(() {
+      var maxScroll = _controller!.position.maxScrollExtent;
+      var pixels = _controller!.position.pixels;
       if (maxScroll == pixels) {
         // load next page
         curPage++;
@@ -76,7 +75,7 @@ class TweetsListPageState extends State<TweetsListPage> {
             return;
           }
           loading = true;
-          Map<String, String> params = new Map();
+          Map<String, String> params = Map();
           params['access_token'] = token;
           params['page'] = "$curPage";
           if (isHot) {
@@ -87,19 +86,19 @@ class TweetsListPageState extends State<TweetsListPage> {
           params['pageSize'] = "20";
           params['dataType'] = "json";
           NetUtils.get(Api.TWEETS_LIST, params: params).then((data) {
-            Map<String, dynamic> obj = json.decode(data);
+            Map<String, dynamic>? obj = json.decode(data);
             if (!isLoadMore) {
               // first load
               if (isHot) {
-                hotTweetsList = obj['tweetlist'];
+                hotTweetsList = obj!['tweetlist'];
               } else {
-                normalTweetsList = obj['tweetlist'];
+                normalTweetsList = obj!['tweetlist'];
               }
             } else {
               // load more
-              List list = new List();
-              list.addAll(normalTweetsList);
-              list.addAll(obj['tweetlist']);
+              List list = [];
+              list.addAll(normalTweetsList!);
+              list.addAll(obj!['tweetlist']);
               normalTweetsList = list;
             }
             filterList(hotTweetsList, true);
@@ -111,12 +110,12 @@ class TweetsListPageState extends State<TweetsListPage> {
   }
 
   // 根据黑名单过滤出新的数组
-  filterList(List<dynamic> objList, bool isHot) {
+  filterList(List<dynamic>? objList, bool isHot) {
     BlackListUtils.getBlackListIds().then((intList) {
       if (intList != null && intList.isNotEmpty && objList != null) {
-        List newList = new List();
+        List newList = [];
         for (dynamic item in objList) {
-          int authorId = item['authorid'];
+          int? authorId = item['authorid'];
           if (!intList.contains(authorId)) {
             newList.add(item);
           }
@@ -155,38 +154,38 @@ class TweetsListPageState extends State<TweetsListPage> {
   }
 
   Widget getRowWidget(Map<String, dynamic> listItem) {
-    var authorRow = new Row(
-      children: <Widget>[
-        new Container(
+    var authorRow = Row(
+      children: [
+        Container(
           width: 35.0,
           height: 35.0,
-          decoration: new BoxDecoration(
+          decoration: BoxDecoration(
             shape: BoxShape.circle,
             color: Colors.transparent,
-            image: new DecorationImage(
-                image: new NetworkImage(listItem['portrait']),
+            image: DecorationImage(
+                image: NetworkImage(listItem['portrait']),
                 fit: BoxFit.cover),
-            border: new Border.all(
+            border: Border.all(
               color: Colors.white,
               width: 2.0,
             ),
           ),
         ),
-        new Padding(
+        Padding(
             padding: const EdgeInsets.fromLTRB(6.0, 0.0, 0.0, 0.0),
-            child: new Text(listItem['author'],
-                style: new TextStyle(
+            child: Text(listItem['author'],
+                style: TextStyle(
                   fontSize: 16.0,
                 ))),
-        new Expanded(
-          child: new Row(
+        Expanded(
+          child: Row(
             mainAxisAlignment: MainAxisAlignment.end,
-            children: <Widget>[
-              new Text(
+            children: [
+              Text(
                 '${listItem['commentCount']}',
                 style: subtitleStyle,
               ),
-              new Image.asset(
+              Image.asset(
                 './images/ic_comment.png',
                 width: 16.0,
                 height: 16.0,
@@ -198,37 +197,37 @@ class TweetsListPageState extends State<TweetsListPage> {
     );
     var _body = listItem['body'];
     _body = clearHtmlContent(_body);
-    var contentRow = new Row(
-      children: <Widget>[
-        new Expanded(
-          child: new Text(_body),
+    var contentRow = Row(
+      children: [
+        Expanded(
+          child: Text(_body),
         )
       ],
     );
-    var timeRow = new Row(
+    var timeRow = Row(
       mainAxisAlignment: MainAxisAlignment.end,
-      children: <Widget>[
-        new Text(
+      children: [
+        Text(
           listItem['pubDate'],
           style: subtitleStyle,
         )
       ],
     );
     var columns = <Widget>[
-      new Padding(
+      Padding(
         padding: const EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 2.0),
         child: authorRow,
       ),
-      new Padding(
+      Padding(
         padding: const EdgeInsets.fromLTRB(52.0, 0.0, 10.0, 0.0),
         child: contentRow,
       ),
     ];
-    String imgSmall = listItem['imgSmall'];
+    String? imgSmall = listItem['imgSmall'];
     if (imgSmall != null && imgSmall.length > 0) {
       // 动弹中有图片
       List<String> list = imgSmall.split(",");
-      List<String> imgUrlList = new List<String>();
+      List<String> imgUrlList = <String>[];
       for (String s in list) {
         if (s.startsWith("http")) {
           imgUrlList.add(s);
@@ -239,16 +238,16 @@ class TweetsListPageState extends State<TweetsListPage> {
       List<Widget> imgList = [];
       List<List<Widget>> rows = [];
       num len = imgUrlList.length;
-      for (var row = 0; row < getRow(len); row++) {
+      for (var row = 0; row < getRow(len as int); row++) {
         List<Widget> rowArr = [];
         for (var col = 0; col < 3; col++) {
           num index = row * 3 + col;
           num screenWidth = MediaQuery.of(context).size.width;
           double cellWidth = (screenWidth - 100) / 3;
           if (index < len) {
-            rowArr.add(new Padding(
+            rowArr.add(Padding(
               padding: const EdgeInsets.all(2.0),
-              child: new Image.network(imgUrlList[index],
+              child: Image.network(imgUrlList[index as int],
                   width: cellWidth, height: cellWidth),
             ));
           }
@@ -256,29 +255,29 @@ class TweetsListPageState extends State<TweetsListPage> {
         rows.add(rowArr);
       }
       for (var row in rows) {
-        imgList.add(new Row(
+        imgList.add(Row(
           children: row,
         ));
       }
-      columns.add(new Padding(
+      columns.add(Padding(
         padding: const EdgeInsets.fromLTRB(52.0, 5.0, 10.0, 0.0),
-        child: new Column(
+        child: Column(
           children: imgList,
         ),
       ));
     }
-    columns.add(new Padding(
+    columns.add(Padding(
       padding: const EdgeInsets.fromLTRB(0.0, 10.0, 10.0, 6.0),
       child: timeRow,
     ));
-    return new InkWell(
-      child: new Column(
+    return InkWell(
+      child: Column(
         children: columns,
       ),
       onTap: () {
         // 跳转到动弹详情
-        Navigator.of(context).push(new MaterialPageRoute(builder: (ctx) {
-          return new TweetDetailPage(
+        Navigator.of(context).push(MaterialPageRoute(builder: (ctx) {
+          return TweetDetailPage(
             tweetData: listItem,
           );
         }));
@@ -287,23 +286,23 @@ class TweetsListPageState extends State<TweetsListPage> {
         showDialog(
           context: context,
           builder: (BuildContext ctx) {
-            return new AlertDialog(
-              title: new Text('提示'),
-              content: new Text('要把\"${listItem['author']}\"关进小黑屋吗?'),
+            return AlertDialog(
+              title: Text('提示'),
+              content: Text('要把\"${listItem['author']}\"关进小黑屋吗?'),
               actions: <Widget>[
-                new FlatButton(
-                  child: new Text(
+                  TextButton(
+                  child: Text(
                     '取消',
-                    style: new TextStyle(color: Colors.red),
+                    style: TextStyle(color: Colors.red),
                   ),
                   onPressed: () {
                     Navigator.of(context).pop();
                   },
                 ),
-                new FlatButton(
-                  child: new Text(
+                  TextButton(
+                  child: Text(
                     '确定',
-                    style: new TextStyle(color: Colors.blue),
+                    style: TextStyle(color: Colors.blue),
                   ),
                   onPressed: () {
                     putIntoBlackHouse(listItem);
@@ -318,13 +317,13 @@ class TweetsListPageState extends State<TweetsListPage> {
 
   // 关进小黑屋
   putIntoBlackHouse(item) {
-    int authorId = item['authorid'];
+    int? authorId = item['authorid'];
     String portrait = "${item['portrait']}";
     String nickname = "${item['author']}";
     DataUtils.getUserInfo().then((info) {
       if (info != null) {
-        int loginUserId = info.id;
-        Map<String, String> params = new Map();
+        int? loginUserId = info.id as int?;
+        Map<String, String?> params = Map();
         params['userid'] = '$loginUserId';
         params['authorid'] = '$authorId';
         params['authoravatar'] = portrait;
@@ -359,14 +358,14 @@ class TweetsListPageState extends State<TweetsListPage> {
     showDialog(
       context: context,
       builder: (BuildContext ctx) {
-        return new AlertDialog(
-          title: new Text('提示'),
-          content: new Text(msg),
+        return AlertDialog(
+          title: Text('提示'),
+          content: Text(msg),
           actions: <Widget>[
-            new FlatButton(
-              child: new Text(
+              TextButton(
+              child: Text(
                 '确定',
-                style: new TextStyle(color: Colors.red),
+                style: TextStyle(color: Colors.red),
               ),
               onPressed: () {
                 Navigator.of(context).pop();
@@ -379,23 +378,23 @@ class TweetsListPageState extends State<TweetsListPage> {
 
   renderHotRow(i) {
     if (i.isOdd) {
-      return new Divider(
+      return Divider(
         height: 1.0,
       );
     } else {
       i = i ~/ 2;
-      return getRowWidget(hotTweetsList[i]);
+      return getRowWidget(hotTweetsList![i]);
     }
   }
 
   renderNormalRow(i) {
     if (i.isOdd) {
-      return new Divider(
+      return Divider(
         height: 1.0,
       );
     } else {
       i = i ~/ 2;
-      return getRowWidget(normalTweetsList[i]);
+      return getRowWidget(normalTweetsList![i]);
     }
   }
 
@@ -417,13 +416,13 @@ class TweetsListPageState extends State<TweetsListPage> {
   Widget getHotListView() {
     if (hotTweetsList == null) {
       getTweetsList(false, true);
-      return new Center(
-        child: new CircularProgressIndicator(),
+      return Center(
+        child: CircularProgressIndicator(),
       );
     } else {
       // 热门动弹列表
-      return new ListView.builder(
-        itemCount: hotTweetsList.length * 2 - 1,
+      return ListView.builder(
+        itemCount: hotTweetsList!.length * 2 - 1,
         itemBuilder: (context, i) => renderHotRow(i),
       );
     }
@@ -432,14 +431,14 @@ class TweetsListPageState extends State<TweetsListPage> {
   Widget getNormalListView() {
     if (normalTweetsList == null) {
       getTweetsList(false, false);
-      return new Center(
-        child: new CircularProgressIndicator(),
+      return Center(
+        child: CircularProgressIndicator(),
       );
     } else {
       // 普通动弹列表
-      return new RefreshIndicator(
-        child: new ListView.builder(
-          itemCount: normalTweetsList.length * 2 - 1,
+      return RefreshIndicator(
+        child: ListView.builder(
+          itemCount: normalTweetsList!.length * 2 - 1,
           itemBuilder: (context, i) => renderNormalRow(i),
           physics: const AlwaysScrollableScrollPhysics(),
           controller: _controller,
@@ -451,37 +450,37 @@ class TweetsListPageState extends State<TweetsListPage> {
   @override
   Widget build(BuildContext context) {
     if (!isUserLogin) {
-      return new Center(
-        child: new Column(
+      return Center(
+        child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            new Container(
+          children: [
+            Container(
               padding: const EdgeInsets.all(10.0),
-              child: new Center(
-                child: new Column(
-                  children: <Widget>[
-                    new Text("由于OSC的openapi限制"),
-                    new Text("必须登录后才能获取动弹信息")
+              child: Center(
+                child: Column(
+                  children: [
+                    Text("由于OSC的openapi限制"),
+                    Text("必须登录后才能获取动弹信息")
                   ],
                 ),
               )
             ),
-            new InkWell(
-              child: new Container(
+            InkWell(
+              child: Container(
                 padding: const EdgeInsets.fromLTRB(15.0, 8.0, 15.0, 8.0),
-                child: new Text("去登录"),
-                decoration: new BoxDecoration(
-                  border: new Border.all(color: Colors.black),
-                  borderRadius: new BorderRadius.all(new Radius.circular(5.0))
+                child: Text("去登录"),
+                decoration: BoxDecoration(
+                  border: Border.all(color: Colors.black),
+                  borderRadius: BorderRadius.all(Radius.circular(5.0))
                 ),
               ),
               onTap: () async {
-                final result = await Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) {
+                final result = await Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) {
                   return LoginPage();
                 }));
                 if (result != null && result == "refresh") {
                   // 通知动弹页面刷新
-                  Constants.eventBus.fire(new LoginEvent());
+                  Constants.eventBus.fire(LoginEvent());
                 }
               },
             ),
@@ -489,21 +488,21 @@ class TweetsListPageState extends State<TweetsListPage> {
         ),
       );
     }
-    return new DefaultTabController(
+    return DefaultTabController(
       length: 2,
-      child: new Scaffold(
-        appBar: new TabBar(
+      child: Scaffold(
+        appBar: TabBar(
           tabs: <Widget>[
-            new Tab(
+            Tab(
               text: "动弹列表",
             ),
-            new Tab(
+            Tab(
               text: "热门动弹",
             )
           ],
         ),
-        body: new TabBarView(
-          children: <Widget>[getNormalListView(), getHotListView()],
+        body: TabBarView(
+          children: [getNormalListView(), getHotListView()],
         )),
     );
   }

+ 3 - 3
lib/pages/UserInfoDetailPage.dart

@@ -4,13 +4,13 @@ import 'package:flutter/material.dart';
 class UserInfoDetailPage extends StatefulWidget {
   @override
   State<StatefulWidget> createState() {
-    return new UserInfoDetailState();
+    return UserInfoDetailState();
   }
 }
 
 class UserInfoDetailState extends State<UserInfoDetailPage> {
   @override
   Widget build(BuildContext context) {
-    return null;
+    return Container();
   }
-}
+}

+ 154 - 0
lib/pages/about_page.dart

@@ -0,0 +1,154 @@
+import 'package:flutter/material.dart';
+import 'CommonWebPage.dart';
+
+/// Description: 关于页面
+/// Time       : 08/14/2022 Sunday
+/// Author     : liuyuqi.gov@msn.cn
+class AboutPage extends StatefulWidget {
+  @override
+  State<StatefulWidget> createState() {
+    return AboutPageState();
+  }
+}
+
+class AboutPageState extends State<AboutPage> {
+  bool showImage = false;
+  TextStyle textStyle = TextStyle(
+      color: Colors.blue,
+      decoration: TextDecoration.combine([TextDecoration.underline]));
+  late Widget authorLink, mayunLink, githubLink;
+  List<String> urls = [];
+  List<String> titles = [];
+
+  AboutPageState() {
+    titles.add("yubo's blog");
+    titles.add("码云");
+    titles.add("GitHub");
+    urls.add("https://yubo725.top");
+    urls.add("https://gitee.com/yubo725");
+    urls.add("https://github.com/yubo725");
+    authorLink = GestureDetector(
+      child: Container(
+        margin: const EdgeInsets.fromLTRB(0.0, 80.0, 0.0, 0.0),
+        child: Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Text("作者:"),
+            Text(
+              "yubo",
+              style: textStyle,
+            ),
+          ],
+        ),
+      ),
+      onTap: getLink(0),
+    );
+    mayunLink = GestureDetector(
+      child: Container(
+        margin: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
+        child: Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Text("码云:"),
+            Text(
+              "https://gitee.com/yubo725",
+              style: textStyle,
+            )
+          ],
+        ),
+      ),
+      onTap: getLink(1),
+    );
+    githubLink = GestureDetector(
+      child: Container(
+        margin: const EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
+        child: Row(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Text("GitHub:"),
+            Text(
+              "https://github.com/yubo725",
+              style: textStyle,
+            ),
+          ],
+        ),
+      ),
+      onTap: getLink(2),
+    );
+  }
+
+  getLink(index) {
+    String url = urls[index];
+    String title = titles[index];
+    return () {
+      Navigator.of(context).push(MaterialPageRoute(builder: (ctx) {
+        return CommonWebPage(title: title, url: url);
+      }));
+    };
+  }
+
+  Widget getImageOrBtn() {
+    if (!showImage) {
+      return Container(
+        child: Center(
+          child: InkWell(
+            child: Container(
+              padding: const EdgeInsets.fromLTRB(15.0, 8.0, 15.0, 8.0),
+              child: Text("不要点我"),
+              decoration: BoxDecoration(
+                  border: Border.all(color: Colors.black),
+                  borderRadius: BorderRadius.all(Radius.circular(5.0))),
+            ),
+            onTap: () {
+              setState(() {
+                showImage = true;
+              });
+            },
+          ),
+        ),
+      );
+    } else {
+      return Image.asset(
+        './images/ic_hongshu.jpg',
+        width: 100.0,
+        height: 100.0,
+      );
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+        appBar: AppBar(
+          title: Text("关于", style: TextStyle(color: Colors.white)),
+          iconTheme: IconThemeData(color: Colors.white),
+        ),
+        body: Center(
+          child: Column(
+            children: [
+              Container(
+                width: 1.0,
+                height: 100.0,
+                color: Colors.transparent,
+              ),
+              Image.asset(
+                './images/ic_osc_logo.png',
+                width: 200.0,
+                height: 56.0,
+              ),
+              Text("基于Google Flutter的开源中国客户端"),
+              authorLink,
+              mayunLink,
+              githubLink,
+              Expanded(flex: 1, child: getImageOrBtn()),
+              Container(
+                  margin: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 15.0),
+                  child: Text(
+                    "本项目仅供学习使用,与开源中国官方无关",
+                    style: TextStyle(fontSize: 12.0),
+                  ))
+            ],
+          ),
+        ));
+  }
+}

+ 93 - 98
lib/pages/BlackHousePage.dart → lib/pages/black_house_page.dart

@@ -1,26 +1,27 @@
+import 'dart:convert';
+
 import 'package:flutter/material.dart';
-import 'package:flutter_osc/constants/Constants.dart';
+import 'package:flutter_osc/model/api.dart';
+import 'package:flutter_osc/model/constants.dart';
 import 'package:flutter_osc/events/LoginEvent.dart';
+import 'package:flutter_osc/pages/login_page.dart';
 import 'package:flutter_osc/util/BlackListUtils.dart';
+import 'package:flutter_osc/util/DataUtils.dart';
+import 'package:flutter_osc/util/NetUtils.dart';
+import 'package:flutter_osc/util/Utf8Utils.dart';
 import 'package:shared_preferences/shared_preferences.dart';
-import '../util/NetUtils.dart';
-import '../api/Api.dart';
-import 'dart:convert';
-import '../pages/LoginPage.dart';
-import '../util/DataUtils.dart';
-import '../util/Utf8Utils.dart';
 
 class BlackHousePage extends StatefulWidget {
   @override
   State<StatefulWidget> createState() {
-    return new BlackHousePageState();
+    return BlackHousePageState();
   }
 }
 
 class BlackHousePageState extends State<BlackHousePage> {
   bool isLogin = true;
-  List blackDataList;
-  TextStyle btnStyle = new TextStyle(color: Colors.white, fontSize: 12.0);
+  List? blackDataList;
+  TextStyle btnStyle = TextStyle(color: Colors.white, fontSize: 12.0);
 
   BlackHousePageState() {
     queryBlackList();
@@ -52,8 +53,8 @@ class BlackHousePageState extends State<BlackHousePage> {
   // 获取用户信息
   getUserInfo() async {
     SharedPreferences sp = await SharedPreferences.getInstance();
-    String accessToken = sp.get(DataUtils.SP_AC_TOKEN);
-    Map<String, String> params = new Map();
+    String? accessToken = sp.get(DataUtils.SP_AC_TOKEN) as String?;
+    Map<String, String?> params = Map();
     params['access_token'] = accessToken;
     NetUtils.get(Api.USER_INFO, params: params).then((data) {
       if (data != null) {
@@ -70,7 +71,7 @@ class BlackHousePageState extends State<BlackHousePage> {
     DataUtils.getUserInfo().then((userInfo) {
       if (userInfo != null) {
         String userId = "${userInfo.id}";
-        Map<String, String> params = new Map();
+        Map<String, String> params = Map();
         params['userid'] = userId;
         params['authorid'] = "$authorId";
         NetUtils.get(Api.DELETE_BLACK, params: params).then((data) {
@@ -95,69 +96,68 @@ class BlackHousePageState extends State<BlackHousePage> {
 
   showResultDialog(String msg) {
     showDialog(
-      context: context,
-      builder: (ctx) {
-        return new AlertDialog(
-          title: new Text('提示'),
-          content: new Text(msg),
-          actions: <Widget>[
-            new FlatButton(
-              child: new Text(
-                '确定',
-                style: new TextStyle(color: Colors.red),
-              ),
-              onPressed: () {
-                Navigator.of(context).pop();
-              },
-            )
-          ],
-        );
-      }
-    );
+        context: context,
+        builder: (ctx) {
+          return AlertDialog(
+            title: Text('提示'),
+            content: Text(msg),
+            actions: <Widget>[
+              TextButton(
+                child: Text(
+                  '确定',
+                  style: TextStyle(color: Colors.red),
+                ),
+                onPressed: () {
+                  Navigator.of(context).pop();
+                },
+              )
+            ],
+          );
+        });
   }
 
   showSetFreeDialog(item) {
-    String name = Utf8Utils.decode(item['authorname']);
+    String? name = Utf8Utils.decode(item['authorname']);
     showDialog(
-      context: context,
-      builder: (BuildContext ctx) {
-        return new AlertDialog(
-          title: new Text('提示'),
-          content: new Text('确定要把\"$name\"放出小黑屋吗?'),
-          actions: <Widget>[
-            new FlatButton(
-              child: new Text(
-                '确定',
-                style: new TextStyle(color: Colors.red),
-              ),
-              onPressed: () {
-                deleteFromBlack(item['authorid']);
-              },
-            )
-          ],
-        );
-      });
+        context: context,
+        builder: (BuildContext ctx) {
+          return AlertDialog(
+            title: Text('提示'),
+            content: Text('确定要把\"$name\"放出小黑屋吗?'),
+            actions: <Widget>[
+              TextButton(
+                child: Text(
+                  '确定',
+                  style: TextStyle(color: Colors.red),
+                ),
+                onPressed: () {
+                  deleteFromBlack(item['authorid']);
+                },
+              )
+            ],
+          );
+        });
   }
 
   Widget getBody() {
     if (!isLogin) {
-      return new Center(
-        child: new InkWell(
-          child: new Container(
+      return Center(
+        child: InkWell(
+          child: Container(
             padding: const EdgeInsets.fromLTRB(15.0, 8.0, 15.0, 8.0),
-            child: new Text("去登录"),
-            decoration: new BoxDecoration(
-                border: new Border.all(color: Colors.black),
-                borderRadius: new BorderRadius.all(new Radius.circular(5.0))
-            ),
+            child: Text("去登录"),
+            decoration: BoxDecoration(
+                border: Border.all(color: Colors.black),
+                borderRadius: BorderRadius.all(Radius.circular(5.0))),
           ),
           onTap: () async {
-            final result = await Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) {
+            final result = await Navigator.of(context)
+                .push(MaterialPageRoute(builder: (BuildContext context) {
               return LoginPage();
             }));
             if (result != null && result == "refresh") {
               // 通知动弹页面刷新
-              Constants.eventBus.fire(new LoginEvent());
+              Constants.eventBus.fire(LoginEvent());
               getUserInfo();
             }
           },
@@ -165,65 +165,60 @@ class BlackHousePageState extends State<BlackHousePage> {
       );
     }
     if (blackDataList == null) {
-      return new Center(
-        child: new CircularProgressIndicator(),
+      return Center(
+        child: CircularProgressIndicator(),
       );
-    } else if (blackDataList.length == 0) {
-      return new Center(
-        child: new Column(
+    } else if (blackDataList!.length == 0) {
+      return Center(
+        child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            new Text("小黑屋中没人..."),
-            new Text("长按动弹列表即可往小黑屋中加人")
-          ],
+          children: [Text("小黑屋中没人..."), Text("长按动弹列表即可往小黑屋中加人")],
         ),
       );
     }
-    return new GridView.count(
+    return GridView.count(
       crossAxisCount: 3,
-      children: new List.generate(blackDataList.length, (index) {
-        String name = Utf8Utils.decode(blackDataList[index]['authorname']);
-        return new Container(
+      children: List.generate(blackDataList!.length, (index) {
+        String name = Utf8Utils.decode(blackDataList![index]['authorname'])!;
+        return Container(
           margin: const EdgeInsets.all(2.0),
           color: Colors.black,
-          child: new Column(
+          child: Column(
             mainAxisAlignment: MainAxisAlignment.center,
-            children: <Widget>[
-              new Container(
+            children: [
+              Container(
                 width: 45.0,
                 height: 45.0,
-                decoration: new BoxDecoration(
+                decoration: BoxDecoration(
                   shape: BoxShape.circle,
                   color: Colors.transparent,
-                  image: new DecorationImage(
-                      image: new NetworkImage(
-                          "${blackDataList[index]['authoravatar']}"),
+                  image: DecorationImage(
+                      image: NetworkImage(
+                          "${blackDataList![index]['authoravatar']}"),
                       fit: BoxFit.cover),
-                  border: new Border.all(
+                  border: Border.all(
                     color: Colors.white,
                     width: 2.0,
                   ),
                 ),
               ),
-              new Container(
+              Container(
                 margin: const EdgeInsets.fromLTRB(0.0, 5.0, 0.0, 5.0),
-                child:
-                    new Text(name, style: new TextStyle(color: Colors.white)),
+                child: Text(name, style: TextStyle(color: Colors.white)),
               ),
-              new InkWell(
-                child: new Container(
+              InkWell(
+                child: Container(
                   padding: const EdgeInsets.fromLTRB(8.0, 5.0, 5.0, 8.0),
-                  child: new Text(
+                  child: Text(
                     "放我出去",
                     style: btnStyle,
                   ),
-                  decoration: new BoxDecoration(
-                      border: new Border.all(color: Colors.white),
-                      borderRadius:
-                          new BorderRadius.all(new Radius.circular(5.0))),
+                  decoration: BoxDecoration(
+                      border: Border.all(color: Colors.white),
+                      borderRadius: BorderRadius.all(Radius.circular(5.0))),
                 ),
                 onTap: () {
-                  showSetFreeDialog(blackDataList[index]);
+                  showSetFreeDialog(blackDataList![index]);
                 },
               ),
             ],
@@ -235,12 +230,12 @@ class BlackHousePageState extends State<BlackHousePage> {
 
   @override
   Widget build(BuildContext context) {
-    return new Scaffold(
-      appBar: new AppBar(
-        title: new Text("动弹小黑屋", style: new TextStyle(color: Colors.white)),
-        iconTheme: new IconThemeData(color: Colors.white),
+    return Scaffold(
+      appBar: AppBar(
+        title: Text("动弹小黑屋", style: TextStyle(color: Colors.white)),
+        iconTheme: IconThemeData(color: Colors.white),
       ),
-      body: new Padding(
+      body: Padding(
         padding: const EdgeInsets.fromLTRB(2.0, 4.0, 2.0, 0.0),
         child: getBody(),
       ),

+ 16 - 16
lib/pages/LoginPage.dart → lib/pages/login_page.dart

@@ -1,6 +1,6 @@
 import 'dart:async';
 import 'package:flutter/material.dart';
-import '../constants/Constants.dart';
+import '../model/constants.dart';
 import 'package:flutter/cupertino.dart';
 import 'dart:convert';
 import '../util/DataUtils.dart';
@@ -8,17 +8,17 @@ import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
 
 class LoginPage extends StatefulWidget {
   @override
-  State<StatefulWidget> createState() => new LoginPageState();
+  State<StatefulWidget> createState() => LoginPageState();
 }
 
 class LoginPageState extends State<LoginPage> {
   int count = 0;
   final int MAX_COUNT = 5;
   bool loading = true;
-  GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey();
-  StreamSubscription<String> _onUrlChanged;
-  StreamSubscription<WebViewStateChanged> _onStateChanged;
-  FlutterWebviewPlugin flutterWebViewPlugin = new FlutterWebviewPlugin();
+  GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
+  late StreamSubscription<String> _onUrlChanged;
+  late StreamSubscription<WebViewStateChanged> _onStateChanged;
+  FlutterWebviewPlugin flutterWebViewPlugin = FlutterWebviewPlugin();
 
   @override
   void initState() {
@@ -31,7 +31,7 @@ class LoginPageState extends State<LoginPage> {
       });
       if (url != null && url.length > 0 && url.contains("osc/osc.php?code=")) {
         // android中onUrlChanged回调时页面已加载完成,由于onStateChanged回调不能用,这里延迟1秒去拿js中的数据,没拿到就再延迟1秒,最多取5次
-        new Timer(const Duration(seconds: 1), parseResult);
+        Timer(const Duration(seconds: 1), parseResult);
       }
     });
   }
@@ -62,7 +62,7 @@ class LoginPageState extends State<LoginPage> {
         }
       } else {
         // 没拿到js中的数据,延迟一秒再拿
-        new Timer(const Duration(seconds: 1), parseResult);
+        Timer(const Duration(seconds: 1), parseResult);
       }
     });
   }
@@ -70,23 +70,23 @@ class LoginPageState extends State<LoginPage> {
   @override
   Widget build(BuildContext context) {
     List<Widget> titleContent = [];
-    titleContent.add(new Text(
+    titleContent.add(Text(
       "登录开源中国",
-      style: new TextStyle(color: Colors.white),
+      style: TextStyle(color: Colors.white),
     ));
     if (loading) {
-      titleContent.add(new CupertinoActivityIndicator());
+      titleContent.add(CupertinoActivityIndicator());
     }
-    titleContent.add(new Container(width: 50.0));
-    return new WebviewScaffold(
+    titleContent.add(Container(width: 50.0));
+    return WebviewScaffold(
       key: _scaffoldKey,
       url: Constants.LOGIN_URL,
-      appBar: new AppBar(
-        title: new Row(
+      appBar: AppBar(
+        title: Row(
           mainAxisAlignment: MainAxisAlignment.center,
           children: titleContent,
         ),
-        iconTheme: new IconThemeData(color: Colors.white),
+        iconTheme: IconThemeData(color: Colors.white),
       ),
       withZoom: true,
       withLocalStorage: true,

+ 57 - 63
lib/pages/MyInfoPage.dart → lib/pages/my_info_page.dart

@@ -1,20 +1,19 @@
 import 'package:flutter/material.dart';
-import 'package:flutter_osc/constants/Constants.dart';
+import 'package:flutter_osc/model/api.dart';
+import 'package:flutter_osc/model/constants.dart';
 import 'package:flutter_osc/events/LoginEvent.dart';
-import 'package:flutter_osc/events/LogoutEvent.dart';
-import '../pages/CommonWebPage.dart';
-import '../pages/LoginPage.dart';
+import 'package:flutter_osc/model/user_info.dart';
+import 'package:flutter_osc/pages/CommonWebPage.dart';
+import 'package:flutter_osc/pages/login_page.dart';
+import 'package:flutter_osc/util/DataUtils.dart';
+import 'package:flutter_osc/util/NetUtils.dart';
 import 'dart:convert';
 import 'package:shared_preferences/shared_preferences.dart';
-import '../api/Api.dart';
-import '../util/NetUtils.dart';
-import '../util/DataUtils.dart';
-import '../model/UserInfo.dart';
 
 class MyInfoPage extends StatefulWidget {
   @override
   State<StatefulWidget> createState() {
-    return new MyInfoPageState();
+    return MyInfoPageState();
   }
 }
 
@@ -35,8 +34,8 @@ class MyInfoPageState extends State<MyInfoPage> {
   var icons = [];
   var userAvatar;
   var userName;
-  var titleTextStyle = new TextStyle(fontSize: 16.0);
-  var rightArrowIcon = new Image.asset(
+  var titleTextStyle = TextStyle(fontSize: 16.0);
+  var rightArrowIcon = Image.asset(
     'images/ic_arrow_right.png',
     width: ARROW_ICON_WIDTH,
     height: ARROW_ICON_WIDTH,
@@ -52,18 +51,18 @@ class MyInfoPageState extends State<MyInfoPage> {
   void initState() {
     super.initState();
     _showUserInfo();
-    Constants.eventBus.on(LogoutEvent).listen((event) {
+    Constants.eventBus.on().listen((event) {
       // 收到退出登录的消息,刷新个人信息显示
       _showUserInfo();
     });
-    Constants.eventBus.on(LoginEvent).listen((event) {
+    Constants.eventBus.on().listen((event) {
       // 收到登录的消息,重新获取个人信息
       getUserInfo();
     });
   }
 
   _showUserInfo() {
-    DataUtils.getUserInfo().then((UserInfo userInfo) {
+    DataUtils.getUserInfo().then((UserInfo? userInfo) {
       if (userInfo != null) {
         print(userInfo.name);
         print(userInfo.avatar);
@@ -81,16 +80,16 @@ class MyInfoPageState extends State<MyInfoPage> {
   }
 
   Widget getIconImage(path) {
-    return new Padding(
+    return Padding(
       padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
-      child: new Image.asset(path,
-          width: IMAGE_ICON_WIDTH, height: IMAGE_ICON_WIDTH),
+      child:
+          Image.asset(path, width: IMAGE_ICON_WIDTH, height: IMAGE_ICON_WIDTH),
     );
   }
 
   @override
   Widget build(BuildContext context) {
-    var listView = new ListView.builder(
+    var listView = ListView.builder(
       itemCount: titles.length * 2,
       itemBuilder: (context, i) => renderRow(i),
     );
@@ -100,8 +99,8 @@ class MyInfoPageState extends State<MyInfoPage> {
   // 获取用户信息
   getUserInfo() async {
     SharedPreferences sp = await SharedPreferences.getInstance();
-    String accessToken = sp.get(DataUtils.SP_AC_TOKEN);
-    Map<String, String> params = new Map();
+    String? accessToken = sp.get(DataUtils.SP_AC_TOKEN) as String?;
+    Map<String, String?> params = Map();
     params['access_token'] = accessToken;
     NetUtils.get(Api.USER_INFO, params: params).then((data) {
       if (data != null) {
@@ -116,16 +115,15 @@ class MyInfoPageState extends State<MyInfoPage> {
   }
 
   _login() async {
-    final result = await Navigator
-        .of(context)
-        .push(new MaterialPageRoute(builder: (context) {
-      return new LoginPage();
+    final result =
+        await Navigator.of(context).push(MaterialPageRoute(builder: (context) {
+      return LoginPage();
     }));
     if (result != null && result == "refresh") {
       // 刷新用户信息
       getUserInfo();
       // 通知动弹页面刷新
-      Constants.eventBus.fire(new LoginEvent());
+      Constants.eventBus.fire(LoginEvent());
     }
   }
 
@@ -133,42 +131,41 @@ class MyInfoPageState extends State<MyInfoPage> {
 
   renderRow(i) {
     if (i == 0) {
-      var avatarContainer = new Container(
+      var avatarContainer = Container(
         color: const Color(0xff63ca6c),
         height: 200.0,
-        child: new Center(
-          child: new Column(
+        child: Center(
+          child: Column(
             mainAxisAlignment: MainAxisAlignment.center,
-            children: <Widget>[
+            children: [
               userAvatar == null
-                  ? new Image.asset(
+                  ? Image.asset(
                       "images/ic_avatar_default.png",
                       width: 60.0,
                     )
-                  : new Container(
+                  : Container(
                       width: 60.0,
                       height: 60.0,
-                      decoration: new BoxDecoration(
+                      decoration: BoxDecoration(
                         shape: BoxShape.circle,
                         color: Colors.transparent,
-                        image: new DecorationImage(
-                            image: new NetworkImage(userAvatar),
-                            fit: BoxFit.cover),
-                        border: new Border.all(
+                        image: DecorationImage(
+                            image: NetworkImage(userAvatar), fit: BoxFit.cover),
+                        border: Border.all(
                           color: Colors.white,
                           width: 2.0,
                         ),
                       ),
                     ),
-              new Text(
+              Text(
                 userName == null ? "点击头像登录" : userName,
-                style: new TextStyle(color: Colors.white, fontSize: 16.0),
+                style: TextStyle(color: Colors.white, fontSize: 16.0),
               ),
             ],
           ),
         ),
       );
-      return new GestureDetector(
+      return GestureDetector(
         onTap: () {
           DataUtils.isLogin().then((isLogin) {
             if (isLogin) {
@@ -185,19 +182,19 @@ class MyInfoPageState extends State<MyInfoPage> {
     }
     --i;
     if (i.isOdd) {
-      return new Divider(
+      return Divider(
         height: 1.0,
       );
     }
     i = i ~/ 2;
     String title = titles[i];
-    var listItemContent = new Padding(
+    var listItemContent = Padding(
       padding: const EdgeInsets.fromLTRB(10.0, 15.0, 10.0, 15.0),
-      child: new Row(
-        children: <Widget>[
+      child: Row(
+        children: [
           icons[i],
-          new Expanded(
-              child: new Text(
+          Expanded(
+              child: Text(
             title,
             style: titleTextStyle,
           )),
@@ -205,13 +202,13 @@ class MyInfoPageState extends State<MyInfoPage> {
         ],
       ),
     );
-    return new InkWell(
+    return InkWell(
       child: listItemContent,
       onTap: () {
         _handleListItemClick(title);
 //        Navigator
 //            .of(context)
-//            .push(new MaterialPageRoute(builder: (context) => new CommonWebPage(title: "Test", url: "https://my.oschina.net/u/815261/blog")));
+//            .push(MaterialPageRoute(builder: (context) => CommonWebPage(title: "Test", url: "https://my.oschina.net/u/815261/blog")));
       },
     );
   }
@@ -220,23 +217,23 @@ class MyInfoPageState extends State<MyInfoPage> {
     showDialog(
         context: context,
         builder: (BuildContext ctx) {
-          return new AlertDialog(
-            title: new Text('提示'),
-            content: new Text('没有登录,现在去登录吗?'),
+          return AlertDialog(
+            title: Text('提示'),
+            content: Text('没有登录,现在去登录吗?'),
             actions: <Widget>[
-              new FlatButton(
-                child: new Text(
+              TextButton(
+                child: Text(
                   '取消',
-                  style: new TextStyle(color: Colors.red),
+                  style: TextStyle(color: Colors.red),
                 ),
                 onPressed: () {
                   Navigator.of(context).pop();
                 },
               ),
-              new FlatButton(
-                child: new Text(
+              TextButton(
+                child: Text(
                   '确定',
-                  style: new TextStyle(color: Colors.blue),
+                  style: TextStyle(color: Colors.blue),
                 ),
                 onPressed: () {
                   Navigator.of(context).pop();
@@ -255,13 +252,10 @@ class MyInfoPageState extends State<MyInfoPage> {
         _showLoginDialog();
       } else {
         DataUtils.getUserInfo().then((info) {
-          Navigator.of(context).push(
-            new MaterialPageRoute(
-              builder: (context) => new CommonWebPage(
-                title: "我的博客",
-                url: "https://my.oschina.net/u/${info.id}/blog"
-              )
-            ));
+          Navigator.of(context).push(MaterialPageRoute(
+              builder: (context) => CommonWebPage(
+                  title: "我的博客",
+                  url: "https://my.oschina.net/u/${info!.id}/blog")));
         });
       }
     });

+ 15 - 15
lib/pages/NewsDetailPage.dart → lib/pages/news_detail_page.dart

@@ -4,22 +4,22 @@ import 'package:flutter_webview_plugin/flutter_webview_plugin.dart';
 
 class NewsDetailPage extends StatefulWidget {
 
-  String id;
+  String? id;
 
-  NewsDetailPage({Key key, this.id}):super(key: key);
+  NewsDetailPage({Key? key, this.id}):super(key: key);
 
   @override
-  State<StatefulWidget> createState() => new NewsDetailPageState(id: this.id);
+  State<StatefulWidget> createState() => NewsDetailPageState(id: this.id);
 }
 
 class NewsDetailPageState extends State<NewsDetailPage> {
 
-  String id;
+  String? id;
   bool loaded = false;
-  String detailDataStr;
-  final flutterWebViewPlugin = new FlutterWebviewPlugin();
+  String? detailDataStr;
+  final flutterWebViewPlugin = FlutterWebviewPlugin();
 
-  NewsDetailPageState({Key key, this.id});
+  NewsDetailPageState({Key? key, this.id});
 
   @override
   void initState() {
@@ -39,19 +39,19 @@ class NewsDetailPageState extends State<NewsDetailPage> {
   @override
   Widget build(BuildContext context) {
     List<Widget> titleContent = [];
-    titleContent.add(new Text("资讯详情", style: new TextStyle(color: Colors.white),));
+    titleContent.add(Text("资讯详情", style: TextStyle(color: Colors.white),));
     if (!loaded) {
-      titleContent.add(new CupertinoActivityIndicator());
+      titleContent.add(CupertinoActivityIndicator());
     }
-    titleContent.add(new Container(width: 50.0));
-    return new WebviewScaffold(
-      url: this.id,
-      appBar: new AppBar(
-        title: new Row(
+    titleContent.add(Container(width: 50.0));
+    return WebviewScaffold(
+      url: this.id!,
+      appBar: AppBar(
+        title: Row(
           mainAxisAlignment: MainAxisAlignment.center,
           children: titleContent,
         ),
-        iconTheme: new IconThemeData(color: Colors.white),
+        iconTheme: IconThemeData(color: Colors.white),
       ),
       withZoom: false,
       withLocalStorage: true,

+ 47 - 47
lib/pages/OfflineActivityPage.dart → lib/pages/offline_activity_page.dart

@@ -1,14 +1,14 @@
 import 'dart:convert';
 import 'package:flutter/material.dart';
 import '../util/NetUtils.dart';
-import '../api/Api.dart';
+import '../model/api.dart';
 import '../pages/CommonWebPage.dart';
 
 // 线下活动
 class OfflineActivityPage extends StatefulWidget {
   @override
   State<StatefulWidget> createState() {
-    return new OfflineActivityPageState();
+    return OfflineActivityPageState();
   }
 }
 
@@ -18,9 +18,9 @@ class OfflineActivityPageState extends State<OfflineActivityPage> {
   String eventTypeRec = "recommend";
   int curPage = 1;
 
-  TextStyle titleTextStyle = new TextStyle(color: Colors.black, fontSize: 18.0);
+  TextStyle titleTextStyle = TextStyle(color: Colors.black, fontSize: 18.0);
 
-  List recData, latestData, ychData;
+  List? recData, latestData, ychData;
 
   @override
   void initState() {
@@ -54,50 +54,50 @@ class OfflineActivityPageState extends State<OfflineActivityPage> {
 
   Widget getRecBody() {
     if (recData == null) {
-      return new Center(child: new CircularProgressIndicator());
-    } else if (recData.length == 0) {
-      return new Center(child: new Text("暂无数据"));
+      return Center(child: CircularProgressIndicator());
+    } else if (recData!.length == 0) {
+      return Center(child: Text("暂无数据"));
     } else {
-      return new ListView.builder(itemBuilder: _renderRecRow, itemCount: recData.length);
+      return ListView.builder(itemBuilder: _renderRecRow, itemCount: recData!.length);
     }
   }
 
   Widget getLatestBody() {
     if (latestData == null) {
-      return new Center(child: new CircularProgressIndicator());
-    } else if (latestData.length == 0) {
-      return new Center(child: new Text("暂无数据"));
+      return Center(child: CircularProgressIndicator());
+    } else if (latestData!.length == 0) {
+      return Center(child: Text("暂无数据"));
     } else {
-      return new ListView.builder(itemBuilder: _renderLatestRow, itemCount: latestData.length);
+      return ListView.builder(itemBuilder: _renderLatestRow, itemCount: latestData!.length);
     }
   }
 
   Widget getYchBody() {
     if (ychData == null) {
-      return new Center(child: new CircularProgressIndicator());
-    } else if (ychData.length == 0) {
-      return new Center(child: new Text("暂无数据"));
+      return Center(child: CircularProgressIndicator());
+    } else if (ychData!.length == 0) {
+      return Center(child: Text("暂无数据"));
     } else {
-      return new ListView.builder(itemBuilder: _renderYchRow, itemCount: ychData.length);
+      return ListView.builder(itemBuilder: _renderYchRow, itemCount: ychData!.length);
     }
   }
 
   Widget getCard(itemData) {
-    return new Card(
-      child: new Column(
-        children: <Widget>[
-          new Image.network(itemData['cover'], fit: BoxFit.cover,),
-          new Container(
+    return Card(
+      child: Column(
+        children: [
+          Image.network(itemData['cover'], fit: BoxFit.cover,),
+          Container(
             margin: const EdgeInsets.fromLTRB(10.0, 5.0, 10.0, 5.0),
             alignment: Alignment.centerLeft,
-            child: new Text(itemData['title'], style: titleTextStyle,),
+            child: Text(itemData['title'], style: titleTextStyle,),
           ),
-          new Container(
+          Container(
               margin: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 5.0),
-              child: new Row(
-                children: <Widget>[
-                  new Expanded(child: new Text(itemData['authorName']), flex: 1,),
-                  new Text(itemData['timeStr'])
+              child: Row(
+                children: [
+                  Expanded(child: Text(itemData['authorName']), flex: 1,),
+                  Text(itemData['timeStr'])
                 ],
               )
           )
@@ -107,8 +107,8 @@ class OfflineActivityPageState extends State<OfflineActivityPage> {
   }
 
   Widget _renderRecRow(BuildContext ctx, int i) {
-    Map itemData = recData[i];
-    return new InkWell(
+    Map itemData = recData![i];
+    return InkWell(
       child: getCard(itemData),
       onTap: () {
         _showDetail(itemData['detailUrl']);
@@ -117,8 +117,8 @@ class OfflineActivityPageState extends State<OfflineActivityPage> {
   }
 
   Widget _renderLatestRow(BuildContext ctx, int i) {
-    Map itemData = latestData[i];
-    return new InkWell(
+    Map itemData = latestData![i];
+    return InkWell(
       child: getCard(itemData),
       onTap: () {
         _showDetail(itemData['detailUrl']);
@@ -127,8 +127,8 @@ class OfflineActivityPageState extends State<OfflineActivityPage> {
   }
 
   Widget _renderYchRow(BuildContext ctx, int i) {
-    Map itemData = ychData[i];
-    return new InkWell(
+    Map itemData = ychData![i];
+    return InkWell(
       child: getCard(itemData),
       onTap: () {
         _showDetail(itemData['detailUrl']);
@@ -137,38 +137,38 @@ class OfflineActivityPageState extends State<OfflineActivityPage> {
   }
 
   _showDetail(detailUrl) {
-    Navigator.of(context).push(new MaterialPageRoute(
+    Navigator.of(context).push(MaterialPageRoute(
       builder: (ctx) {
-        return new CommonWebPage(title: '活动详情', url: detailUrl);
+        return CommonWebPage(title: '活动详情', url: detailUrl);
       }
     ));
   }
 
   @override
   Widget build(BuildContext context) {
-    return new Scaffold(
-      appBar: new AppBar(
-        title: new Text("线下活动", style: new TextStyle(color: Colors.white)),
-        iconTheme: new IconThemeData(color: Colors.white),
+    return Scaffold(
+      appBar: AppBar(
+        title: Text("线下活动", style: TextStyle(color: Colors.white)),
+        iconTheme: IconThemeData(color: Colors.white),
       ),
-      body: new DefaultTabController(
+      body: DefaultTabController(
         length: 3,
-        child: new Scaffold(
-            appBar: new TabBar(
+        child: Scaffold(
+            appBar: TabBar(
               tabs: <Widget>[
-                new Tab(
+                Tab(
                   text: "强力推荐",
                 ),
-                new Tab(
+                Tab(
                   text: "最新活动",
                 ),
-                new Tab(
+                Tab(
                   text: "源创会",
                 )
               ],
             ),
-            body: new TabBarView(
-              children: <Widget>[
+            body: TabBarView(
+              children: [
                 getRecBody(),
                 getLatestBody(),
                 getYchBody()

+ 32 - 32
lib/pages/SettingsPage.dart → lib/pages/setting_page.dart

@@ -1,9 +1,9 @@
 import 'package:flutter/material.dart';
-import 'package:flutter_osc/constants/Constants.dart';
+import 'package:flutter_osc/model/constants.dart';
 import 'package:flutter_osc/events/LogoutEvent.dart';
 import '../util/DataUtils.dart';
 
-class SettingsPage extends StatelessWidget {
+class SettingPage extends StatelessWidget {
   static const String TAG_START = "startDivider";
   static const String TAG_END = "endDivider";
   static const String TAG_CENTER = "centerDivider";
@@ -12,8 +12,8 @@ class SettingsPage extends StatelessWidget {
   static const double IMAGE_ICON_WIDTH = 30.0;
   static const double ARROW_ICON_WIDTH = 16.0;
 
-  final titleTextStyle = new TextStyle(fontSize: 16.0);
-  final rightArrowIcon = new Image.asset(
+  final titleTextStyle = TextStyle(fontSize: 16.0);
+  final rightArrowIcon = Image.asset(
     'images/ic_arrow_right.png',
     width: ARROW_ICON_WIDTH,
     height: ARROW_ICON_WIDTH,
@@ -21,76 +21,76 @@ class SettingsPage extends StatelessWidget {
 
   List listData = [];
 
-  SettingsPage() {
+  SettingPage() {
     listData.add(TAG_BLANK);
     listData.add(TAG_START);
-    listData.add(
-        new ListItem(title: '退出登录', icon: 'images/ic_discover_nearby.png'));
+    listData
+        .add(ListItem(title: '退出登录', icon: 'images/ic_discover_nearby.png'));
     listData.add(TAG_END);
   }
 
   Widget getIconImage(path) {
-    return new Padding(
+    return Padding(
       padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
-      child: new Image.asset(path,
-          width: IMAGE_ICON_WIDTH, height: IMAGE_ICON_WIDTH),
+      child:
+          Image.asset(path, width: IMAGE_ICON_WIDTH, height: IMAGE_ICON_WIDTH),
     );
   }
 
   _renderRow(BuildContext ctx, int i) {
     var item = listData[i];
     if (item is String) {
-      Widget w = new Divider(
+      Widget w = Divider(
         height: 1.0,
       );
       switch (item) {
         case TAG_START:
-          w = new Divider(
+          w = Divider(
             height: 1.0,
           );
           break;
         case TAG_END:
-          w = new Divider(
+          w = Divider(
             height: 1.0,
           );
           break;
         case TAG_CENTER:
-          w = new Padding(
+          w = Padding(
             padding: const EdgeInsets.fromLTRB(50.0, 0.0, 0.0, 0.0),
-            child: new Divider(
+            child: Divider(
               height: 1.0,
             ),
           );
           break;
         case TAG_BLANK:
-          w = new Container(
+          w = Container(
             height: 20.0,
           );
           break;
       }
       return w;
     } else if (item is ListItem) {
-      var listItemContent = new Padding(
+      var listItemContent = Padding(
         padding: const EdgeInsets.fromLTRB(10.0, 15.0, 10.0, 15.0),
-        child: new Row(
-          children: <Widget>[
+        child: Row(
+          children: [
             getIconImage(item.icon),
-            new Expanded(
-                child: new Text(
-              item.title,
+            Expanded(
+                child: Text(
+              item.title!,
               style: titleTextStyle,
             )),
             rightArrowIcon
           ],
         ),
       );
-      return new InkWell(
+      return InkWell(
         onTap: () {
-          String title = item.title;
+          String? title = item.title;
           if (title == '退出登录') {
             DataUtils.clearLoginInfo().then((arg) {
               Navigator.of(ctx).pop();
-              Constants.eventBus.fire(new LogoutEvent());
+              Constants.eventBus.fire(LogoutEvent());
               print("event fired!");
             });
           }
@@ -102,12 +102,12 @@ class SettingsPage extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return new Scaffold(
-      appBar: new AppBar(
-        title: new Text("设置", style: new TextStyle(color: Colors.white)),
-        iconTheme: new IconThemeData(color: Colors.white),
+    return Scaffold(
+      appBar: AppBar(
+        title: Text("设置", style: TextStyle(color: Colors.white)),
+        iconTheme: IconThemeData(color: Colors.white),
       ),
-      body: new ListView.builder(
+      body: ListView.builder(
         itemBuilder: (ctx, i) => _renderRow(ctx, i),
         itemCount: listData.length,
       ),
@@ -116,7 +116,7 @@ class SettingsPage extends StatelessWidget {
 }
 
 class ListItem {
-  String icon;
-  String title;
+  String? icon;
+  String? title;
   ListItem({this.icon, this.title});
 }

+ 20 - 20
lib/util/BlackListUtils.dart

@@ -7,11 +7,11 @@ class BlackListUtils {
   static final String SP_BLACK_LIST = "blackList";
 
   // 将对象数组转化为整型数组
-  static List<int> convert(List objList) {
+  static List<int?> convert(List objList) {
     if (objList == null || objList.isEmpty) {
-      return new List<int>();
+      return <int>[];
     }
-    List<int> intList = new List();
+    List<int?> intList = [];
     for (var obj in objList) {
       intList.add(obj['authorid']);
     }
@@ -19,11 +19,11 @@ class BlackListUtils {
   }
 
   // 字符串转化为整型数组
-  static List<int> _str2intList(String str) {
+  static List<int?>? _str2intList(String? str) {
     if (str != null && str.length > 0) {
       List<String> list = str.split(",");
       if (list != null && list.isNotEmpty) {
-        List<int> intList = new List();
+        List<int?> intList = [];
         for (String s in list) {
           intList.add(int.parse(s));
         }
@@ -34,12 +34,12 @@ class BlackListUtils {
   }
 
   // 整型数组转化为字符串
-  static String _intList2Str(List<int> list) {
+  static String? _intList2Str(List<int?> list) {
     if (list == null || list.isEmpty) {
       return null;
     }
-    StringBuffer sb = new StringBuffer();
-    for (int id in list) {
+    StringBuffer sb = StringBuffer();
+    for (int? id in list) {
       sb.write("$id,");
     }
     String result = sb.toString();
@@ -47,8 +47,8 @@ class BlackListUtils {
   }
 
   // 保存黑名单的id
-  static Future<String> saveBlackListIds(List<int> list) async {
-    String str = _intList2Str(list);
+  static Future<String?> saveBlackListIds(List<int?> list) async {
+    String? str = _intList2Str(list);
     if (str != null) {
       SharedPreferences sp = await SharedPreferences.getInstance();
       sp.setString(SP_BLACK_LIST, str);
@@ -60,9 +60,9 @@ class BlackListUtils {
   }
 
   // 获取本地保存的黑名单id数据
-  static Future<List<int>> getBlackListIds() async {
+  static Future<List<int?>?> getBlackListIds() async {
     SharedPreferences sp = await SharedPreferences.getInstance();
-    String str = sp.getString(SP_BLACK_LIST);
+    String? str = sp.getString(SP_BLACK_LIST);
     if (str != null && str.length > 0) {
       return _str2intList(str);
     }
@@ -70,31 +70,31 @@ class BlackListUtils {
   }
 
   // 向黑名单中添加一个id
-  static Future<List<int>> addBlackId(int id) async {
-    List<int> list = await getBlackListIds();
+  static Future<List<int?>?> addBlackId(int? id) async {
+    List<int?>? list = await getBlackListIds();
     if (list != null && list.isNotEmpty) {
       if (!list.contains(id)) {
         list.add(id);
-        String str = await saveBlackListIds(list);
+        String? str = await saveBlackListIds(list);
         return _str2intList(str);
       } else {
         return list;
       }
     } else {
-      List<int> l = new List();
+      List<int?> l = [];
       l.add(id);
-      String str = await saveBlackListIds(l);
+      String? str = await saveBlackListIds(l);
       return _str2intList(str);
     }
   }
 
   // 向黑名单中移除一个id
-  static Future<List<int>> removeBlackId(int id) async {
-    List<int> list = await getBlackListIds();
+  static Future<List<int?>?> removeBlackId(int? id) async {
+    List<int?>? list = await getBlackListIds();
     if (list != null && list.isNotEmpty) {
       if (list.contains(id)) {
         list.remove(id);
-        String str = await saveBlackListIds(list);
+        String? str = await saveBlackListIds(list);
         return _str2intList(str);
       }
     }

+ 11 - 11
lib/util/DataUtils.dart

@@ -1,6 +1,6 @@
+import 'package:flutter_osc/model/user_info.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 import 'dart:async';
-import '../model/UserInfo.dart';
 
 class DataUtils {
   static final String SP_AC_TOKEN = "accessToken";
@@ -27,11 +27,11 @@ class DataUtils {
       String refreshToken = data['refresh_token'];
       await sp.setString(SP_RE_TOKEN, refreshToken);
       num uid = data['uid'];
-      await sp.setInt(SP_UID, uid);
+      await sp.setInt(SP_UID, uid as int);
       String tokenType = data['tokenType'];
       await sp.setString(SP_TOKEN_TYPE, tokenType);
       num expiresIn = data['expires_in'];
-      await sp.setInt(SP_EXPIRES_IN, expiresIn);
+      await sp.setInt(SP_EXPIRES_IN, expiresIn as int);
 
       await sp.setBool(SP_IS_LOGIN, true);
     }
@@ -48,7 +48,7 @@ class DataUtils {
   }
 
   // 保存用户个人信息
-  static Future<UserInfo> saveUserInfo(Map data) async {
+  static Future<UserInfo?> saveUserInfo(Map? data) async {
     if (data != null) {
       SharedPreferences sp = await SharedPreferences.getInstance();
       String name = data['name'];
@@ -59,13 +59,13 @@ class DataUtils {
       String email = data['email'];
       String url = data['url'];
       await sp.setString(SP_USER_NAME, name);
-      await sp.setInt(SP_USER_ID, id);
+      await sp.setInt(SP_USER_ID, id as int);
       await sp.setString(SP_USER_GENDER, gender);
       await sp.setString(SP_USER_AVATAR, avatar);
       await sp.setString(SP_USER_LOC, location);
       await sp.setString(SP_USER_EMAIL, email);
       await sp.setString(SP_USER_URL, url);
-      UserInfo userInfo = new UserInfo(
+      UserInfo userInfo = UserInfo(
         id: id,
         name: name,
         gender: gender,
@@ -80,13 +80,13 @@ class DataUtils {
   }
 
   // 获取用户信息
-  static Future<UserInfo> getUserInfo() async {
+  static Future<UserInfo?> getUserInfo() async {
     SharedPreferences sp = await SharedPreferences.getInstance();
-    bool isLogin = sp.getBool(SP_IS_LOGIN);
+    bool? isLogin = sp.getBool(SP_IS_LOGIN);
     if (isLogin == null || !isLogin) {
       return null;
     }
-    UserInfo userInfo = new UserInfo();
+    UserInfo userInfo = UserInfo();
     userInfo.id = sp.getInt(SP_USER_ID);
     userInfo.name = sp.getString(SP_USER_NAME);
     userInfo.avatar = sp.getString(SP_USER_AVATAR);
@@ -99,11 +99,11 @@ class DataUtils {
 
   static Future<bool> isLogin() async {
     SharedPreferences sp = await SharedPreferences.getInstance();
-    bool b = sp.getBool(SP_IS_LOGIN);
+    bool? b = sp.getBool(SP_IS_LOGIN);
     return b != null && b;
   }
 
-  static Future<String> getAccessToken() async {
+  static Future<String?> getAccessToken() async {
     SharedPreferences sp = await SharedPreferences.getInstance();
     return sp.getString(SP_AC_TOKEN);
   }

+ 7 - 7
lib/util/NetUtils.dart

@@ -2,9 +2,9 @@ import 'dart:async';
 import 'package:http/http.dart' as http;
 
 class NetUtils {
-  static Future<String> get(String url, {Map<String, String> params}) async {
+  static Future<String> get(String url, {Map<String, String?>? params}) async {
     if (params != null && params.isNotEmpty) {
-      StringBuffer sb = new StringBuffer("?");
+      StringBuffer sb = StringBuffer("?");
       params.forEach((key, value) {
         sb.write("$key" + "=" + "$value" + "&");
       });
@@ -12,12 +12,12 @@ class NetUtils {
       paramStr = paramStr.substring(0, paramStr.length - 1);
       url += paramStr;
     }
-    http.Response res = await http.get(url);
+    http.Response res = await http.get(Uri.parse(url));
     return res.body;
   }
-  
-  static Future<String> post(String url, {Map<String, String> params}) async {
-    http.Response res = await http.post(url, body: params);
+
+  static Future<String> post(String url, {Map<String, String?>? params}) async {
+    http.Response res = await http.post(Uri.parse(url), body: params);
     return res.body;
   }
-}
+}

+ 4 - 4
lib/util/Utf8Utils.dart

@@ -2,12 +2,12 @@ import 'dart:convert';
 
 class Utf8Utils {
   
-  static String encode(String origin) {
+  static String? encode(String origin) {
     if (origin == null || origin.length == 0) {
       return null;
     }
     List<int> list = utf8.encode(origin);
-    StringBuffer sb = new StringBuffer();
+    StringBuffer sb = StringBuffer();
     for (int i in list) {
       sb.write("$i,");
     }
@@ -15,13 +15,13 @@ class Utf8Utils {
     return result.substring(0, result.length - 1);
   }
   
-  static String decode(String encodeStr) {
+  static String? decode(String? encodeStr) {
     if (encodeStr == null || encodeStr.length == 0) {
       return null;
     }
     List<String> list = encodeStr.split(",");
     if (list != null && list.isNotEmpty) {
-      List<int> intList = new List();
+      List<int> intList = [];
       for (String s in list) {
         intList.add(int.parse(s));
       }

+ 16 - 14
lib/widgets/CircleImage.dart

@@ -1,7 +1,6 @@
-import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 
-enum CircleImageType {network, asset}
+enum CircleImageType { network, asset }
 
 class CircleImage extends StatefulWidget {
   double width;
@@ -9,11 +8,15 @@ class CircleImage extends StatefulWidget {
   String path;
   CircleImageType type; // network, asset
 
-  CircleImage({@required this.width, @required this.height, @required this.path, @required this.type});
+  CircleImage(
+      {required this.width,
+      required this.height,
+      required this.path,
+      required this.type});
 
   @override
   State<StatefulWidget> createState() {
-    return null;
+    return CircleImageState();
   }
 }
 
@@ -22,25 +25,24 @@ class CircleImageState extends State<CircleImage> {
   Widget build(BuildContext context) {
     var img;
     if (widget.type == CircleImageType.network) {
-      img = new Image.network(widget.path, width: widget.width, height: widget.height);
+      img = Image.network(widget.path,
+          width: widget.width, height: widget.height);
     } else {
-      img = new Image.asset(widget.path, width: widget.width, height: widget.height);
+      img =
+          Image.asset(widget.path, width: widget.width, height: widget.height);
     }
-    return new Container(
+    return Container(
       width: widget.width,
       height: widget.height,
-      decoration: new BoxDecoration(
+      decoration: BoxDecoration(
         shape: BoxShape.circle,
         color: Colors.blue,
-        image: new DecorationImage(
-            image: img,
-            fit: BoxFit.cover
-        ),
-        border: new Border.all(
+        image: DecorationImage(image: img, fit: BoxFit.cover),
+        border: Border.all(
           color: Colors.white,
           width: 2.0,
         ),
       ),
     );
   }
-}
+}

+ 8 - 8
lib/widgets/CommonEndLine.dart

@@ -3,18 +3,18 @@ import 'package:flutter/material.dart';
 class CommonEndLine extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
-    return new Container(
+    return Container(
       color: const Color(0xFFEEEEEE),
       padding: const EdgeInsets.fromLTRB(5.0, 15.0, 5.0, 15.0),
-      child: new Row(
-        children: <Widget>[
-          new Expanded(
-            child: new Divider(height: 10.0,),
+      child: Row(
+        children: [
+          Expanded(
+            child: Divider(height: 10.0,),
             flex: 1,
           ),
-          new Text("我也是有底线的"),
-          new Expanded(
-            child: new Divider(height: 10.0,),
+          Text("我也是有底线的"),
+          Expanded(
+            child: Divider(height: 10.0,),
             flex: 1,
           ),
         ],

+ 29 - 29
lib/widgets/MyDrawer.dart

@@ -1,32 +1,32 @@
 
 import 'package:flutter/material.dart';
-import '../pages/AboutPage.dart';
-import '../pages/BlackHousePage.dart';
+import '../pages/about_page.dart';
+import '../pages/black_house_page.dart';
 import '../pages/PublishTweetPage.dart';
-import '../pages/SettingsPage.dart';
+import '../pages/setting_page.dart';
 
 class MyDrawer extends StatelessWidget {
 
   static const double IMAGE_ICON_WIDTH = 30.0;
   static const double ARROW_ICON_WIDTH = 16.0;
-  var rightArrowIcon = new Image.asset('images/ic_arrow_right.png', width: ARROW_ICON_WIDTH, height: ARROW_ICON_WIDTH,);
+  var rightArrowIcon = Image.asset('images/ic_arrow_right.png', width: ARROW_ICON_WIDTH, height: ARROW_ICON_WIDTH,);
   List menuTitles = ['发布动弹', '动弹小黑屋', '关于', '设置'];
   List menuIcons = ['./images/leftmenu/ic_fabu.png', './images/leftmenu/ic_xiaoheiwu.png', './images/leftmenu/ic_about.png', './images/leftmenu/ic_settings.png'];
-  TextStyle menuStyle = new TextStyle(
+  TextStyle menuStyle = TextStyle(
     fontSize: 15.0,
   );
 
   @override
   Widget build(BuildContext context) {
-    return new ConstrainedBox(
+    return ConstrainedBox(
       constraints: const BoxConstraints.expand(width: 304.0),
-      child: new Material(
+      child: Material(
         elevation: 16.0,
-        child: new Container(
-          decoration: new BoxDecoration(
+        child: Container(
+          decoration: BoxDecoration(
             color: const Color(0xFFFFFFFF),
           ),
-          child: new ListView.builder(
+          child: ListView.builder(
             itemCount: menuTitles.length * 2 + 1,
             itemBuilder: renderRow,
           ),
@@ -36,17 +36,17 @@ class MyDrawer extends StatelessWidget {
   }
 
   Widget getIconImage(path) {
-    return new Padding(
+    return Padding(
       padding: const EdgeInsets.fromLTRB(2.0, 0.0, 6.0, 0.0),
-      child: new Image.asset(path, width: 28.0, height: 28.0),
+      child: Image.asset(path, width: 28.0, height: 28.0),
     );
   }
 
   Widget renderRow(BuildContext context, int index) {
     if (index == 0) {
       // render cover image
-      var img = new Image.asset('./images/cover_img.jpg', width: 304.0, height: 304.0,);
-      return new Container(
+      var img = Image.asset('./images/cover_img.jpg', width: 304.0, height: 304.0,);
+      return Container(
         width: 304.0,
         height: 304.0,
         margin: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 10.0),
@@ -55,56 +55,56 @@ class MyDrawer extends StatelessWidget {
     }
     index -= 1;
     if (index.isOdd) {
-      return new Divider();
+      return Divider();
     }
     index = index ~/2;
 
-    var listItemContent =  new Padding(
+    var listItemContent =  Padding(
       padding: const EdgeInsets.fromLTRB(10.0, 15.0, 10.0, 15.0),
-      child: new Row(
-        children: <Widget>[
+      child: Row(
+        children: [
           getIconImage(menuIcons[index]),
-          new Expanded(
-              child: new Text(menuTitles[index], style: menuStyle,)
+          Expanded(
+              child: Text(menuTitles[index], style: menuStyle,)
           ),
           rightArrowIcon
         ],
       ),
     );
 
-    return new InkWell(
+    return InkWell(
       child: listItemContent,
       onTap: () {
         switch (index) {
           case 0:
             // 发布动弹
-            Navigator.of(context).push(new MaterialPageRoute(
+            Navigator.of(context).push(MaterialPageRoute(
                 builder: (ctx) {
-                  return new PublishTweetPage();
+                  return PublishTweetPage();
                 }
             ));
             break;
           case 1:
             // 小黑屋
-            Navigator.of(context).push(new MaterialPageRoute(
+            Navigator.of(context).push(MaterialPageRoute(
                 builder: (ctx) {
-                  return new BlackHousePage();
+                  return BlackHousePage();
                 }
             ));
             break;
           case 2:
             // 关于
-            Navigator.of(context).push(new MaterialPageRoute(
+            Navigator.of(context).push(MaterialPageRoute(
                 builder: (ctx) {
-                  return new AboutPage();
+                  return AboutPage();
                 }
             ));
             break;
           case 3:
             // 设置
-            Navigator.of(context).push(new MaterialPageRoute(
+            Navigator.of(context).push(MaterialPageRoute(
                 builder: (ctx) {
-                  return new SettingsPage();
+              return SettingPage();
                 }
             ));
             break;

+ 21 - 21
lib/widgets/SlideView.dart

@@ -1,5 +1,5 @@
 import 'package:flutter/material.dart';
-import '../pages/NewsDetailPage.dart';
+import '../pages/news_detail_page.dart';
 
 class SlideView extends StatefulWidget {
   var data;
@@ -10,13 +10,13 @@ class SlideView extends StatefulWidget {
 
   @override
   State<StatefulWidget> createState() {
-    return new SlideViewState(data);
+    return SlideViewState(data);
   }
 }
 
 class SlideViewState extends State<SlideView> with SingleTickerProviderStateMixin {
-  TabController tabController;
-  List slideData;
+  TabController? tabController;
+  List? slideData;
 
   SlideViewState(data) {
     slideData = data;
@@ -25,47 +25,47 @@ class SlideViewState extends State<SlideView> with SingleTickerProviderStateMixi
   @override
   void initState() {
     super.initState();
-    tabController = new TabController(length: slideData == null ? 0 : slideData.length, vsync: this);
+    tabController = TabController(length: slideData == null ? 0 : slideData!.length, vsync: this);
   }
 
   @override
   void dispose() {
-    tabController.dispose();
+    tabController!.dispose();
     super.dispose();
   }
 
   Widget generateCard() {
-    return new Card(
+    return Card(
       color: Colors.blue,
-      child: new Image.asset("images/ic_avatar_default.png", width: 20.0, height: 20.0,),
+      child: Image.asset("images/ic_avatar_default.png", width: 20.0, height: 20.0,),
     );
   }
 
   @override
   Widget build(BuildContext context) {
     List<Widget> items = [];
-    if (slideData != null && slideData.length > 0) {
-      for (var i = 0; i < slideData.length; i++) {
-        var item = slideData[i];
+    if (slideData != null && slideData!.length > 0) {
+      for (var i = 0; i < slideData!.length; i++) {
+        var item = slideData![i];
         var imgUrl = item['imgUrl'];
         var title = item['title'];
         var detailUrl = item['detailUrl'];
-        items.add(new GestureDetector(
+        items.add(GestureDetector(
           onTap: () {
             // 点击跳转到详情
-            Navigator.of(context).push(new MaterialPageRoute(
-                builder: (ctx) => new NewsDetailPage(id: detailUrl)
+            Navigator.of(context).push(MaterialPageRoute(
+                builder: (ctx) => NewsDetailPage(id: detailUrl)
             ));
           },
-          child: new Stack(
-            children: <Widget>[
-              new Image.network(imgUrl),
-              new Container(
+          child: Stack(
+            children: [
+              Image.network(imgUrl),
+              Container(
                 width: MediaQuery.of(context).size.width,
                 color: const Color(0x50000000),
-                child: new Padding(
+                child: Padding(
                   padding: const EdgeInsets.all(6.0),
-                  child: new Text(title, style: new TextStyle(color: Colors.white, fontSize: 15.0)),
+                  child: Text(title, style: TextStyle(color: Colors.white, fontSize: 15.0)),
                 )
               )
             ],
@@ -73,7 +73,7 @@ class SlideViewState extends State<SlideView> with SingleTickerProviderStateMixi
         ));
       }
     }
-    return new TabBarView(
+    return TabBarView(
       controller: tabController,
       children: items,
     );

+ 245 - 30
pubspec.lock

@@ -1,5 +1,5 @@
 # Generated by pub
-# See https://www.dartlang.org/tools/pub/glossary#lockfile
+# See https://dart.dev/tools/pub/glossary#lockfile
 packages:
   async:
     dependency: transitive
@@ -7,115 +7,316 @@ packages:
       name: async
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "2.1.0"
+    version: "2.8.2"
   barcode_scan:
     dependency: "direct main"
     description:
       name: barcode_scan
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.0.8"
+    version: "3.0.1"
   boolean_selector:
     dependency: transitive
     description:
       name: boolean_selector
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.0.4"
+    version: "2.1.0"
+  characters:
+    dependency: transitive
+    description:
+      name: characters
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.2.0"
   charcode:
     dependency: transitive
     description:
       name: charcode
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.1.2"
+    version: "1.3.1"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.1.0"
   collection:
     dependency: transitive
     description:
       name: collection
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.14.11"
+    version: "1.16.0"
+  cross_file:
+    dependency: transitive
+    description:
+      name: cross_file
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.3.3+1"
   cupertino_icons:
     dependency: "direct main"
     description:
       name: cupertino_icons
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.1.2"
+    version: "1.0.5"
   event_bus:
     dependency: "direct main"
     description:
       name: event_bus
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.1.0"
+    version: "2.0.0"
+  fake_async:
+    dependency: transitive
+    description:
+      name: fake_async
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "1.3.0"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.1"
+  file:
+    dependency: transitive
+    description:
+      name: file
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "6.1.2"
+  fixnum:
+    dependency: transitive
+    description:
+      name: fixnum
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.10.11"
   flutter:
     dependency: "direct main"
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_plugin_android_lifecycle:
+    dependency: transitive
+    description:
+      name: flutter_plugin_android_lifecycle
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.7"
   flutter_test:
     dependency: "direct dev"
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_web_plugins:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.0"
   flutter_webview_plugin:
     dependency: "direct main"
     description:
       name: flutter_webview_plugin
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.3.7"
+    version: "0.4.0"
+  http:
+    dependency: "direct main"
+    description:
+      name: http
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.13.5"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.0.1"
   image_picker:
     dependency: "direct main"
     description:
       name: image_picker
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.4.12+1"
+    version: "0.8.5+3"
+  image_picker_android:
+    dependency: transitive
+    description:
+      name: image_picker_android
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.8.5+2"
+  image_picker_for_web:
+    dependency: transitive
+    description:
+      name: image_picker_for_web
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.8"
+  image_picker_ios:
+    dependency: transitive
+    description:
+      name: image_picker_ios
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.8.5+6"
+  image_picker_platform_interface:
+    dependency: transitive
+    description:
+      name: image_picker_platform_interface
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.6.1"
+  js:
+    dependency: transitive
+    description:
+      name: js
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.6.4"
   matcher:
     dependency: transitive
     description:
       name: matcher
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.12.5"
+    version: "0.12.11"
+  material_color_utilities:
+    dependency: transitive
+    description:
+      name: material_color_utilities
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.1.4"
   meta:
     dependency: transitive
     description:
       name: meta
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.1.6"
+    version: "1.7.0"
   path:
     dependency: transitive
     description:
       name: path
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.6.2"
-  pedantic:
+    version: "1.8.1"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.7"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.4"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.2"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "3.1.0"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.2"
+  process:
     dependency: transitive
     description:
-      name: pedantic
+      name: process
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.5.0"
-  quiver:
+    version: "4.2.4"
+  protobuf:
     dependency: transitive
     description:
-      name: quiver
+      name: protobuf
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "2.0.2"
+    version: "1.1.4"
   shared_preferences:
     dependency: "direct main"
     description:
       name: shared_preferences
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.4.3"
+    version: "2.0.15"
+  shared_preferences_android:
+    dependency: transitive
+    description:
+      name: shared_preferences_android
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.12"
+  shared_preferences_ios:
+    dependency: transitive
+    description:
+      name: shared_preferences_ios
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  shared_preferences_linux:
+    dependency: transitive
+    description:
+      name: shared_preferences_linux
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
+  shared_preferences_macos:
+    dependency: transitive
+    description:
+      name: shared_preferences_macos
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.4"
+  shared_preferences_platform_interface:
+    dependency: transitive
+    description:
+      name: shared_preferences_platform_interface
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.0"
+  shared_preferences_web:
+    dependency: transitive
+    description:
+      name: shared_preferences_web
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.4"
+  shared_preferences_windows:
+    dependency: transitive
+    description:
+      name: shared_preferences_windows
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.1.1"
   sky_engine:
     dependency: transitive
     description: flutter
@@ -127,56 +328,70 @@ packages:
       name: source_span
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.5.5"
+    version: "1.8.2"
   stack_trace:
     dependency: transitive
     description:
       name: stack_trace
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.9.3"
+    version: "1.10.0"
   stream_channel:
     dependency: transitive
     description:
       name: stream_channel
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "2.0.0"
+    version: "2.1.0"
   string_scanner:
     dependency: transitive
     description:
       name: string_scanner
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.0.4"
+    version: "1.1.0"
   term_glyph:
     dependency: transitive
     description:
       name: term_glyph
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.1.0"
+    version: "1.2.0"
   test_api:
     dependency: transitive
     description:
       name: test_api
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "0.2.4"
+    version: "0.4.9"
   typed_data:
     dependency: transitive
     description:
       name: typed_data
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "1.1.6"
+    version: "1.3.1"
   vector_math:
     dependency: transitive
     description:
       name: vector_math
       url: "https://pub.flutter-io.cn"
     source: hosted
-    version: "2.0.8"
+    version: "2.1.2"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.7.0"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "0.2.0+1"
 sdks:
-  dart: ">=2.2.0 <3.0.0"
-  flutter: ">=0.1.4 <2.0.0"
+  dart: ">=2.17.0 <3.0.0"
+  flutter: ">=3.0.0"

+ 13 - 46
pubspec.yaml

@@ -1,38 +1,31 @@
 name: flutter_osc
 description: A new Flutter application.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+version: 1.0.0+1
+
+environment:
+  sdk: '>=2.12.0 <3.0.0'
 
 dependencies:
   flutter:
     sdk: flutter
 
-  # The following adds the Cupertino Icons font to your application.
-  # Use with the CupertinoIcons class for iOS style icons.
-  cupertino_icons: ^0.1.0
-
-  flutter_webview_plugin: "^0.3.7"
-  image_picker: "^0.4.1"
-#  fluttertoast: "^2.0.3"
-  shared_preferences: "^0.4.1"
-  event_bus: "^1.1.0"
-  barcode_scan: "^0.0.4"
+  cupertino_icons: ^1.0.5
+  flutter_webview_plugin: ^0.4.0
+  image_picker: ^0.8.5+3
+#  fluttertoast: ^2.0.3
+  shared_preferences: ^2.0.15
+  event_bus: ^2.0.0
+  barcode_scan: ^3.0.1
+  http: ^0.13.5
 
 dev_dependencies:
   flutter_test:
     sdk: flutter
 
-
-# For information on the generic Dart part of this file, see the
-# following page: https://www.dartlang.org/tools/pub/pubspec
-
-# The following section is specific to Flutter.
 flutter:
-
-  # The following line ensures that the Material Icons font is
-  # included with your application, so that you can use the icons in
-  # the material Icons class.
   uses-material-design: true
 
-  # To add assets to your application, add an assets section, like this:
   assets:
     - images/ic_avatar_default.png
     - images/ic_nav_news_normal.png
@@ -67,29 +60,3 @@ flutter:
     - images/leftmenu/ic_settings.png
     - images/ic_osc_logo.png
     - images/ic_add_pics.png
-
-  # An image asset can refer to one or more resolution-specific "variants", see
-  # https://flutter.io/assets-and-images/#resolution-aware.
-
-  # For details regarding adding assets from package dependencies, see
-  # https://flutter.io/assets-and-images/#from-packages
-
-  # To add custom fonts to your application, add a fonts section here,
-  # in this "flutter" section. Each entry in this list should have a
-  # "family" key with the font family name, and a "fonts" key with a
-  # list giving the asset and other descriptors for the font. For
-  # example:
-#  fonts:
-#    - family: Msyh
-#      fonts:
-#        - asset: fonts/Msyh.ttf
-  #       - asset: fonts/Schyler-Italic.ttf
-  #         style: italic
-  #   - family: Trajan Pro
-  #     fonts:
-  #       - asset: fonts/TrajanPro.ttf
-  #       - asset: fonts/TrajanPro_Bold.ttf
-  #         weight: 700
-  #
-  # For details regarding fonts from package dependencies, 
-  # see https://flutter.io/custom-fonts/#from-packages

+ 1 - 1
test/widget_test.dart

@@ -12,7 +12,7 @@ import 'package:flutter_osc/main.dart';
 void main() {
   testWidgets('Counter increments smoke test', (WidgetTester tester) async {
     // Build our app and trigger a frame.
-    await tester.pumpWidget(new MyOSCClient());
+    await tester.pumpWidget(MyOSCClient());
 
     // Verify that our counter starts at 0.
     expect(find.text('0'), findsOneWidget);

Some files were not shown because too many files changed in this diff