Преглед изворни кода

fix some bugs
decrypt
encrypt (not complete)

ignalxy пре 4 година
родитељ
комит
d3b3e2389a

+ 41 - 0
lib/common/cipher.dart

@@ -0,0 +1,41 @@
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:encrypt/encrypt_io.dart';
+import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+import 'package:encrypt/encrypt.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:pointycastle/asymmetric/api.dart';
+
+import 'global.dart';
+
+Future<RSAPrivateKey?> getRSAPrivateKey(String username) async {
+  try {
+    final storage = FlutterSecureStorage();
+    String? s = await storage.read(key: 'e2ee chat private key of $username');
+    Directory tempDir = await getTemporaryDirectory();
+    String tempPath = tempDir.path;
+    String filePath = '$tempPath/public.pem';
+    final file = File(filePath);
+    final privateKey = await parseKeyFromFile<RSAPrivateKey>(filePath);
+    file.delete();
+    return privateKey;
+  } catch (e) {
+    debug('get rsa private key failed: $e');
+  }
+}
+
+Future<RSAPublicKey?> getRSAPublicKey(String contents) async {
+  try {
+    Directory tempDir = await getTemporaryDirectory();
+    String tempPath = tempDir.path;
+    String filePath = '$tempPath/private.pem';
+    final file = File(filePath);
+    file.writeAsString(contents);
+    final publicKey = await parseKeyFromFile<RSAPublicKey>(filePath);
+    return publicKey;
+  } catch (e) {
+    debug('get rsa public key failed: $e');
+  }
+}

+ 5 - 7
lib/common/global.dart

@@ -4,10 +4,9 @@ import 'dart:convert';
 import 'package:dio/dio.dart';
 import 'package:e2ee_chat/common/api.dart';
 import 'package:e2ee_chat/model/profile.dart';
-import 'package:e2ee_chat/objectbox.g.dart';
 import 'package:flutter/material.dart';
-import 'package:objectbox/objectbox.dart';
 import 'package:permission_handler/permission_handler.dart';
+import 'package:shared_preferences/shared_preferences.dart';
 
 import '../presenter/login.dart';
 
@@ -71,12 +70,12 @@ class Global {
 
     bool status = await checkPermission();
     assert(status, "permission error");
-    final store = await openStore();
 
-    Box box = store.box<Profile>();
-    profile = box.get(profileId) ?? Profile();
+    final prefs = await SharedPreferences.getInstance();
+    String? json = prefs.getString("profile");
+    profile = json!=null ? Profile.fromJson(jsonDecode(json)) : Profile();
     profile.isLogin = false;
-    debug('Init profile: id: ${profile.id}, username: ${profile.username}, isLogout: ${profile.isLogout}');
+    debug('Init profile: username: ${profile.username}, isLogout: ${profile.isLogout}');
 
 
     await Api.init();
@@ -91,7 +90,6 @@ class Global {
       debug('Init login failed');
     }
      */
-    store.close();
     debug('Global init end');
   }
 

+ 0 - 1
lib/main.dart

@@ -1,4 +1,3 @@
-import 'package:e2ee_chat/objectbox.g.dart';
 import 'package:e2ee_chat/view/add_friend.dart';
 import 'package:e2ee_chat/view/user_chat.dart';
 import 'package:flutter/material.dart';

+ 3 - 3
lib/model/friendship.dart

@@ -1,12 +1,12 @@
-import 'package:objectbox/objectbox.dart';
-
 import 'message.dart';
 import 'user.dart';
 
+/*
 @Entity()
 class FriendShip {
   int id = 0;
   final user0 = ToOne<User>();
   final user1 = ToOne<User>();
   final messages = ToMany<Message>();
-}
+}
+ */

+ 3 - 3
lib/model/group.dart

@@ -1,12 +1,12 @@
-import 'package:objectbox/objectbox.dart';
-
 import 'message.dart';
 import 'user.dart';
 
+/*
 @Entity()
 class Group {
   int id = 0;
   final name = "";
   final members = ToMany<User>();
   final messages = ToMany<GroupMessage>();
-}
+}
+ */

+ 44 - 13
lib/model/message.dart

@@ -1,25 +1,55 @@
 import 'dart:convert';
 
+import 'package:e2ee_chat/common/cipher.dart';
+import 'package:json_annotation/json_annotation.dart';
 import 'package:dash_chat/dash_chat.dart';
-import 'package:e2ee_chat/common/global.dart';
-import 'package:objectbox/objectbox.dart';
+import 'package:encrypt/encrypt.dart';
+import 'package:pointycastle/asymmetric/api.dart';
 
-import '../objectbox.g.dart';
-import 'group.dart';
-import 'user.dart';
+part 'message.g.dart';
 
-@Entity()
+@JsonSerializable()
 class Message {
-  int id = 0;
-  String plaintext = "";
-  final from = ToOne<User>();
-  final to = ToOne<User>();
+  Message(this.from, this.to, this.cipher, this.cipherText, this.publicKey, this.iv);
 
-  @Transient()
-  ChatMessage get chatMessage => ChatMessage.fromJson(jsonDecode(plaintext));
+  factory Message.encrypt(String from, String to, String plaintext, String publicKey) {
+    // TODO: encrypt
+    String cipher = "";
+    String cipherText = "";
+    String publicKey = "";
+    String iv = "";
+    return Message(from, to, cipher, cipherText, publicKey, iv);
+  }
+
+  factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(json);
+  Map<String, dynamic> toJson() => _$MessageToJson(this);
+
+  String from;
+  String to;
+  String cipher;
+  String cipherText;
+  String publicKey;
+  String iv;
+
+  Future<ChatMessage?> get chatMessage async {
+    ChatMessage? _message;
+    final RSAPrivateKey? _privateKey = await getRSAPrivateKey(from);
+    if (_privateKey != null) {
+      final _publicKey = (await getRSAPublicKey(publicKey))!;
+      final _rsaEncrypter = Encrypter(
+          RSA(publicKey: _publicKey, privateKey: _privateKey));
+      final _keyBase64 = _rsaEncrypter.decrypt64(cipher);
+      final _key = Key.fromBase64(_keyBase64);
+      final _iv = IV.fromBase64(iv);
+      final _aesEncrypter = Encrypter(AES(_key));
+      final _decrypted = _aesEncrypter.decrypt64(cipherText, iv: _iv);
+      _message = ChatMessage.fromJson(jsonDecode(_decrypted));
+    }
+    return _message;
+  }
 }
 
-@Entity()
+/*
 class GroupMessage {
   int id = 0;
   String plaintext = "";
@@ -29,3 +59,4 @@ class GroupMessage {
   @Transient()
   ChatMessage get chatMessage => ChatMessage.fromJson(jsonDecode(plaintext));
 }
+*/

+ 31 - 12
lib/model/profile.dart

@@ -1,26 +1,26 @@
+import 'dart:convert';
+
 import 'package:flutter/material.dart';
 import 'package:flutter_secure_storage/flutter_secure_storage.dart';
-
+import 'package:json_annotation/json_annotation.dart';
 import 'package:e2ee_chat/common/global.dart';
-import 'package:objectbox/objectbox.dart';
 
 import 'user.dart';
 
-
-@Entity()
 class Profile {
-  int id = 0;
-  int theme = Global.themes[0].value;
-  @Transient()
+  Profile({
+    this.theme = 0xFF2196F3, this.user, this.isLogin = false, this.isLogout = false,
+    this.locale = const Locale("zh", "CN")
+  });
+
+  int theme;
   User? user;
-  bool isLogin = false;
-  bool isLogout = false;
-  Locale? locale;
+  bool isLogin;
+  bool isLogout;
+  Locale locale;
 
-  @Transient()
   String? get username => user?.username;
 
-  @Transient()
   Future<String?> get token async {
     if (user == null) return null;
     final storage = FlutterSecureStorage();
@@ -33,4 +33,23 @@ class Profile {
   }
 
   String get _tokenKey => "e2ee_chat token of $username";
+
+  factory Profile.fromJson(Map<String, dynamic> json) {
+    return Profile(
+      theme: json["theme"],
+      user: User.fromJson(jsonDecode(json["user"])),
+      isLogin: json["isLogin"],
+      isLogout: json["isLogout"],
+      locale: Locale(json["lang"], json["country"])
+    );
+  }
+
+  Map<String, dynamic> toJson() => {
+    "theme": theme,
+    "user": jsonEncode(user?.toJson()),
+    "isLogin": isLogin,
+    "isLogout": isLogout,
+    "lang": locale.languageCode,
+    "country": locale.countryCode
+  };
 }

+ 11 - 11
lib/model/user.dart

@@ -1,21 +1,22 @@
 import 'package:dash_chat/dash_chat.dart';
-import 'package:e2ee_chat/common/global.dart';
-import 'package:e2ee_chat/objectbox.g.dart';
+import 'package:json_annotation/json_annotation.dart';
 import 'package:e2ee_chat/presenter/contact.dart';
-import 'package:objectbox/objectbox.dart';
-import 'package:e2ee_chat/common/api.dart';
 
 import 'message.dart';
 
-@Entity()
+part 'user.g.dart';
+
+@JsonSerializable()
 class User {
   User(this.username, {this.bio, this.phone, this.avatar});
-  int id = 0;
-  @Unique()
+
+  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
+  Map<String, dynamic> toJson() => _$UserToJson(this);
+
   final String username;
-  final friends = ToMany<User>();
-  final messages = ToMany<Message>();
-  final groupMessages = ToMany<GroupMessage>();
+  final friends = <User>[];
+  final messages = <Message>[];
+  // final groupMessages = <GroupMessage>[];
   String? bio;
   String? phone;
   String? avatar;
@@ -27,5 +28,4 @@ class User {
 
   Future<bool> refreshProfile() => UserProfilePresenter(this).refresh();
 
-  // TODO: avatar
 }

+ 0 - 287
lib/objectbox-model.json

@@ -1,287 +0,0 @@
-{
-  "_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
-  "_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
-  "_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
-  "entities": [
-    {
-      "id": "2:1438354990151910015",
-      "lastPropertyId": "9:2124161694143580615",
-      "name": "Profile",
-      "properties": [
-        {
-          "id": "1:3873481118333862410",
-          "name": "id",
-          "type": 6,
-          "flags": 1
-        },
-        {
-          "id": "2:9078004558710481468",
-          "name": "theme",
-          "type": 6
-        },
-        {
-          "id": "4:5923665807684456265",
-          "name": "isLogin",
-          "type": 1
-        },
-        {
-          "id": "7:4763561980566319174",
-          "name": "isLogout",
-          "type": 1
-        }
-      ],
-      "relations": []
-    },
-    {
-      "id": "5:8880211362757189177",
-      "lastPropertyId": "10:374576085041052636",
-      "name": "Message",
-      "properties": [
-        {
-          "id": "1:8816894358087325317",
-          "name": "id",
-          "type": 6,
-          "flags": 1
-        },
-        {
-          "id": "8:8678749043281739962",
-          "name": "fromId",
-          "type": 11,
-          "flags": 520,
-          "indexId": "19:8639940058127995637",
-          "relationTarget": "User"
-        },
-        {
-          "id": "9:5782107643295328726",
-          "name": "toId",
-          "type": 11,
-          "flags": 520,
-          "indexId": "20:304254955908714790",
-          "relationTarget": "User"
-        },
-        {
-          "id": "10:374576085041052636",
-          "name": "plaintext",
-          "type": 9
-        }
-      ],
-      "relations": []
-    },
-    {
-      "id": "6:6066676571331973763",
-      "lastPropertyId": "9:8156592908306452117",
-      "name": "User",
-      "properties": [
-        {
-          "id": "1:5757871925438229578",
-          "name": "id",
-          "type": 6,
-          "flags": 1
-        },
-        {
-          "id": "3:2365120802531976993",
-          "name": "username",
-          "type": 9,
-          "flags": 2080,
-          "indexId": "9:7432421428375491492"
-        },
-        {
-          "id": "4:3332680204867820806",
-          "name": "isDND",
-          "type": 1
-        },
-        {
-          "id": "5:2234651531374642771",
-          "name": "isStick",
-          "type": 1
-        },
-        {
-          "id": "6:3504407138147737485",
-          "name": "isSpecialAttention",
-          "type": 1
-        },
-        {
-          "id": "7:1645455969656989260",
-          "name": "bio",
-          "type": 9
-        },
-        {
-          "id": "8:1358020543347548551",
-          "name": "phone",
-          "type": 9
-        },
-        {
-          "id": "9:8156592908306452117",
-          "name": "avatar",
-          "type": 9
-        }
-      ],
-      "relations": [
-        {
-          "id": "2:3118435353931894829",
-          "name": "friends",
-          "targetId": "6:6066676571331973763"
-        },
-        {
-          "id": "5:8362659550242546106",
-          "name": "messages",
-          "targetId": "5:8880211362757189177"
-        },
-        {
-          "id": "6:6570620621500888428",
-          "name": "groupMessages",
-          "targetId": "8:8842794649328270120"
-        }
-      ]
-    },
-    {
-      "id": "7:1497196184348190204",
-      "lastPropertyId": "1:8442786984080711776",
-      "name": "Group",
-      "properties": [
-        {
-          "id": "1:8442786984080711776",
-          "name": "id",
-          "type": 6,
-          "flags": 1
-        }
-      ],
-      "relations": [
-        {
-          "id": "3:7924032496731598926",
-          "name": "members",
-          "targetId": "6:6066676571331973763"
-        },
-        {
-          "id": "4:1657013690878572102",
-          "name": "messages",
-          "targetId": "8:8842794649328270120"
-        }
-      ]
-    },
-    {
-      "id": "8:8842794649328270120",
-      "lastPropertyId": "9:4521061296978960561",
-      "name": "GroupMessage",
-      "properties": [
-        {
-          "id": "1:8727865543427007275",
-          "name": "id",
-          "type": 6,
-          "flags": 1
-        },
-        {
-          "id": "7:3385606654272810305",
-          "name": "userId",
-          "type": 11,
-          "flags": 520,
-          "indexId": "17:8821791717138159999",
-          "relationTarget": "User"
-        },
-        {
-          "id": "8:3058571589698982963",
-          "name": "groupId",
-          "type": 11,
-          "flags": 520,
-          "indexId": "18:1064437420014320687",
-          "relationTarget": "Group"
-        },
-        {
-          "id": "9:4521061296978960561",
-          "name": "plaintext",
-          "type": 9
-        }
-      ],
-      "relations": []
-    },
-    {
-      "id": "9:2478855716396571806",
-      "lastPropertyId": "5:89425193393960797",
-      "name": "FriendShip",
-      "properties": [
-        {
-          "id": "1:5265335145979968165",
-          "name": "id",
-          "type": 6,
-          "flags": 1
-        },
-        {
-          "id": "4:6943551359011057155",
-          "name": "user0Id",
-          "type": 11,
-          "flags": 520,
-          "indexId": "15:6350205891372750325",
-          "relationTarget": "User"
-        },
-        {
-          "id": "5:89425193393960797",
-          "name": "user1Id",
-          "type": 11,
-          "flags": 520,
-          "indexId": "16:5223993210314820647",
-          "relationTarget": "User"
-        }
-      ],
-      "relations": [
-        {
-          "id": "7:4471061252621927376",
-          "name": "messages",
-          "targetId": "5:8880211362757189177"
-        }
-      ]
-    }
-  ],
-  "lastEntityId": "9:2478855716396571806",
-  "lastIndexId": "21:4046871049442788311",
-  "lastRelationId": "7:4471061252621927376",
-  "lastSequenceId": "0:0",
-  "modelVersion": 5,
-  "modelVersionParserMinimum": 5,
-  "retiredEntityUids": [
-    3444477729893015694,
-    5044745765388820377,
-    2132486004932842474
-  ],
-  "retiredIndexUids": [
-    2181766053148811865,
-    6495021264194887400,
-    5329740598468773345,
-    8703247978603696283,
-    459640529781791232,
-    5268783855356873237,
-    7769527806721188121,
-    7233565214869368113,
-    6309601695170211538,
-    205849996938840771,
-    4046871049442788311
-  ],
-  "retiredPropertyUids": [
-    5463014948149082651,
-    2305308568754167021,
-    649621747167423523,
-    4818206049188692305,
-    2230815448876041069,
-    5034484793468406763,
-    754684519442805673,
-    214180290351070734,
-    7647214962273172849,
-    6701330857882848509,
-    2182219019195059976,
-    7982216815340584307,
-    7721473969164711791,
-    609986407749732855,
-    8078506595736209118,
-    5514462395021006262,
-    1148609827653786396,
-    7294884137191806532,
-    7501600871221400279,
-    5148143939128616318,
-    634385368395524800,
-    4388824818686674479,
-    8861377786907255369,
-    4222660909971782394,
-    2124161694143580615
-  ],
-  "retiredRelationUids": [],
-  "version": 1
-}

+ 0 - 666
lib/objectbox.g.dart

@@ -1,666 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-// ignore_for_file: camel_case_types
-
-import 'dart:typed_data';
-
-import 'package:objectbox/flatbuffers/flat_buffers.dart' as fb;
-import 'package:objectbox/internal.dart'; // generated code can access "internal" functionality
-import 'package:objectbox/objectbox.dart';
-import 'package:objectbox_flutter_libs/objectbox_flutter_libs.dart';
-
-import 'model/friendship.dart';
-import 'model/group.dart';
-import 'model/message.dart';
-import 'model/profile.dart';
-import 'model/user.dart';
-
-export 'package:objectbox/objectbox.dart'; // so that callers only have to import this file
-
-final _entities = <ModelEntity>[
-  ModelEntity(
-      id: const IdUid(2, 1438354990151910015),
-      name: 'Profile',
-      lastPropertyId: const IdUid(9, 2124161694143580615),
-      flags: 0,
-      properties: <ModelProperty>[
-        ModelProperty(
-            id: const IdUid(1, 3873481118333862410),
-            name: 'id',
-            type: 6,
-            flags: 1),
-        ModelProperty(
-            id: const IdUid(2, 9078004558710481468),
-            name: 'theme',
-            type: 6,
-            flags: 0),
-        ModelProperty(
-            id: const IdUid(4, 5923665807684456265),
-            name: 'isLogin',
-            type: 1,
-            flags: 0),
-        ModelProperty(
-            id: const IdUid(7, 4763561980566319174),
-            name: 'isLogout',
-            type: 1,
-            flags: 0)
-      ],
-      relations: <ModelRelation>[],
-      backlinks: <ModelBacklink>[]),
-  ModelEntity(
-      id: const IdUid(5, 8880211362757189177),
-      name: 'Message',
-      lastPropertyId: const IdUid(10, 374576085041052636),
-      flags: 0,
-      properties: <ModelProperty>[
-        ModelProperty(
-            id: const IdUid(1, 8816894358087325317),
-            name: 'id',
-            type: 6,
-            flags: 1),
-        ModelProperty(
-            id: const IdUid(8, 8678749043281739962),
-            name: 'fromId',
-            type: 11,
-            flags: 520,
-            indexId: const IdUid(19, 8639940058127995637),
-            relationTarget: 'User'),
-        ModelProperty(
-            id: const IdUid(9, 5782107643295328726),
-            name: 'toId',
-            type: 11,
-            flags: 520,
-            indexId: const IdUid(20, 304254955908714790),
-            relationTarget: 'User'),
-        ModelProperty(
-            id: const IdUid(10, 374576085041052636),
-            name: 'plaintext',
-            type: 9,
-            flags: 0)
-      ],
-      relations: <ModelRelation>[],
-      backlinks: <ModelBacklink>[]),
-  ModelEntity(
-      id: const IdUid(6, 6066676571331973763),
-      name: 'User',
-      lastPropertyId: const IdUid(9, 8156592908306452117),
-      flags: 0,
-      properties: <ModelProperty>[
-        ModelProperty(
-            id: const IdUid(1, 5757871925438229578),
-            name: 'id',
-            type: 6,
-            flags: 1),
-        ModelProperty(
-            id: const IdUid(3, 2365120802531976993),
-            name: 'username',
-            type: 9,
-            flags: 2080,
-            indexId: const IdUid(9, 7432421428375491492)),
-        ModelProperty(
-            id: const IdUid(4, 3332680204867820806),
-            name: 'isDND',
-            type: 1,
-            flags: 0),
-        ModelProperty(
-            id: const IdUid(5, 2234651531374642771),
-            name: 'isStick',
-            type: 1,
-            flags: 0),
-        ModelProperty(
-            id: const IdUid(6, 3504407138147737485),
-            name: 'isSpecialAttention',
-            type: 1,
-            flags: 0),
-        ModelProperty(
-            id: const IdUid(7, 1645455969656989260),
-            name: 'bio',
-            type: 9,
-            flags: 0),
-        ModelProperty(
-            id: const IdUid(8, 1358020543347548551),
-            name: 'phone',
-            type: 9,
-            flags: 0),
-        ModelProperty(
-            id: const IdUid(9, 8156592908306452117),
-            name: 'avatar',
-            type: 9,
-            flags: 0)
-      ],
-      relations: <ModelRelation>[
-        ModelRelation(
-            id: const IdUid(2, 3118435353931894829),
-            name: 'friends',
-            targetId: const IdUid(6, 6066676571331973763)),
-        ModelRelation(
-            id: const IdUid(5, 8362659550242546106),
-            name: 'messages',
-            targetId: const IdUid(5, 8880211362757189177)),
-        ModelRelation(
-            id: const IdUid(6, 6570620621500888428),
-            name: 'groupMessages',
-            targetId: const IdUid(8, 8842794649328270120))
-      ],
-      backlinks: <ModelBacklink>[]),
-  ModelEntity(
-      id: const IdUid(7, 1497196184348190204),
-      name: 'Group',
-      lastPropertyId: const IdUid(1, 8442786984080711776),
-      flags: 0,
-      properties: <ModelProperty>[
-        ModelProperty(
-            id: const IdUid(1, 8442786984080711776),
-            name: 'id',
-            type: 6,
-            flags: 1)
-      ],
-      relations: <ModelRelation>[
-        ModelRelation(
-            id: const IdUid(3, 7924032496731598926),
-            name: 'members',
-            targetId: const IdUid(6, 6066676571331973763)),
-        ModelRelation(
-            id: const IdUid(4, 1657013690878572102),
-            name: 'messages',
-            targetId: const IdUid(8, 8842794649328270120))
-      ],
-      backlinks: <ModelBacklink>[]),
-  ModelEntity(
-      id: const IdUid(8, 8842794649328270120),
-      name: 'GroupMessage',
-      lastPropertyId: const IdUid(9, 4521061296978960561),
-      flags: 0,
-      properties: <ModelProperty>[
-        ModelProperty(
-            id: const IdUid(1, 8727865543427007275),
-            name: 'id',
-            type: 6,
-            flags: 1),
-        ModelProperty(
-            id: const IdUid(7, 3385606654272810305),
-            name: 'userId',
-            type: 11,
-            flags: 520,
-            indexId: const IdUid(17, 8821791717138159999),
-            relationTarget: 'User'),
-        ModelProperty(
-            id: const IdUid(8, 3058571589698982963),
-            name: 'groupId',
-            type: 11,
-            flags: 520,
-            indexId: const IdUid(18, 1064437420014320687),
-            relationTarget: 'Group'),
-        ModelProperty(
-            id: const IdUid(9, 4521061296978960561),
-            name: 'plaintext',
-            type: 9,
-            flags: 0)
-      ],
-      relations: <ModelRelation>[],
-      backlinks: <ModelBacklink>[]),
-  ModelEntity(
-      id: const IdUid(9, 2478855716396571806),
-      name: 'FriendShip',
-      lastPropertyId: const IdUid(5, 89425193393960797),
-      flags: 0,
-      properties: <ModelProperty>[
-        ModelProperty(
-            id: const IdUid(1, 5265335145979968165),
-            name: 'id',
-            type: 6,
-            flags: 1),
-        ModelProperty(
-            id: const IdUid(4, 6943551359011057155),
-            name: 'user0Id',
-            type: 11,
-            flags: 520,
-            indexId: const IdUid(15, 6350205891372750325),
-            relationTarget: 'User'),
-        ModelProperty(
-            id: const IdUid(5, 89425193393960797),
-            name: 'user1Id',
-            type: 11,
-            flags: 520,
-            indexId: const IdUid(16, 5223993210314820647),
-            relationTarget: 'User')
-      ],
-      relations: <ModelRelation>[
-        ModelRelation(
-            id: const IdUid(7, 4471061252621927376),
-            name: 'messages',
-            targetId: const IdUid(5, 8880211362757189177))
-      ],
-      backlinks: <ModelBacklink>[])
-];
-
-/// Open an ObjectBox store with the model declared in this file.
-Future<Store> openStore(
-        {String? directory,
-        int? maxDBSizeInKB,
-        int? fileMode,
-        int? maxReaders,
-        bool queriesCaseSensitiveDefault = true,
-        String? macosApplicationGroup}) async =>
-    Store(getObjectBoxModel(),
-        directory: directory ?? (await defaultStoreDirectory()).path,
-        maxDBSizeInKB: maxDBSizeInKB,
-        fileMode: fileMode,
-        maxReaders: maxReaders,
-        queriesCaseSensitiveDefault: queriesCaseSensitiveDefault,
-        macosApplicationGroup: macosApplicationGroup);
-
-/// ObjectBox model definition, pass it to [Store] - Store(getObjectBoxModel())
-ModelDefinition getObjectBoxModel() {
-  final model = ModelInfo(
-      entities: _entities,
-      lastEntityId: const IdUid(9, 2478855716396571806),
-      lastIndexId: const IdUid(21, 4046871049442788311),
-      lastRelationId: const IdUid(7, 4471061252621927376),
-      lastSequenceId: const IdUid(0, 0),
-      retiredEntityUids: const [
-        3444477729893015694,
-        5044745765388820377,
-        2132486004932842474
-      ],
-      retiredIndexUids: const [
-        2181766053148811865,
-        6495021264194887400,
-        5329740598468773345,
-        8703247978603696283,
-        459640529781791232,
-        5268783855356873237,
-        7769527806721188121,
-        7233565214869368113,
-        6309601695170211538,
-        205849996938840771,
-        4046871049442788311
-      ],
-      retiredPropertyUids: const [
-        5463014948149082651,
-        2305308568754167021,
-        649621747167423523,
-        4818206049188692305,
-        2230815448876041069,
-        5034484793468406763,
-        754684519442805673,
-        214180290351070734,
-        7647214962273172849,
-        6701330857882848509,
-        2182219019195059976,
-        7982216815340584307,
-        7721473969164711791,
-        609986407749732855,
-        8078506595736209118,
-        5514462395021006262,
-        1148609827653786396,
-        7294884137191806532,
-        7501600871221400279,
-        5148143939128616318,
-        634385368395524800,
-        4388824818686674479,
-        8861377786907255369,
-        4222660909971782394,
-        2124161694143580615
-      ],
-      retiredRelationUids: const [],
-      modelVersion: 5,
-      modelVersionParserMinimum: 5,
-      version: 1);
-
-  final bindings = <Type, EntityDefinition>{
-    Profile: EntityDefinition<Profile>(
-        model: _entities[0],
-        toOneRelations: (Profile object) => [],
-        toManyRelations: (Profile object) => {},
-        getId: (Profile object) => object.id,
-        setId: (Profile object, int id) {
-          object.id = id;
-        },
-        objectToFB: (Profile object, fb.Builder fbb) {
-          fbb.startTable(10);
-          fbb.addInt64(0, object.id);
-          fbb.addInt64(1, object.theme);
-          fbb.addBool(3, object.isLogin);
-          fbb.addBool(6, object.isLogout);
-          fbb.finish(fbb.endTable());
-          return object.id;
-        },
-        objectFromFB: (Store store, ByteData fbData) {
-          final buffer = fb.BufferContext(fbData);
-          final rootOffset = buffer.derefObject(0);
-
-          final object = Profile()
-            ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0)
-            ..theme = const fb.Int64Reader().vTableGet(buffer, rootOffset, 6, 0)
-            ..isLogin =
-                const fb.BoolReader().vTableGet(buffer, rootOffset, 10, false)
-            ..isLogout =
-                const fb.BoolReader().vTableGet(buffer, rootOffset, 16, false);
-
-          return object;
-        }),
-    Message: EntityDefinition<Message>(
-        model: _entities[1],
-        toOneRelations: (Message object) => [object.from, object.to],
-        toManyRelations: (Message object) => {},
-        getId: (Message object) => object.id,
-        setId: (Message object, int id) {
-          object.id = id;
-        },
-        objectToFB: (Message object, fb.Builder fbb) {
-          final plaintextOffset = fbb.writeString(object.plaintext);
-          fbb.startTable(11);
-          fbb.addInt64(0, object.id);
-          fbb.addInt64(7, object.from.targetId);
-          fbb.addInt64(8, object.to.targetId);
-          fbb.addOffset(9, plaintextOffset);
-          fbb.finish(fbb.endTable());
-          return object.id;
-        },
-        objectFromFB: (Store store, ByteData fbData) {
-          final buffer = fb.BufferContext(fbData);
-          final rootOffset = buffer.derefObject(0);
-
-          final object = Message()
-            ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0)
-            ..plaintext =
-                const fb.StringReader().vTableGet(buffer, rootOffset, 22, '');
-          object.from.targetId =
-              const fb.Int64Reader().vTableGet(buffer, rootOffset, 18, 0);
-          object.from.attach(store);
-          object.to.targetId =
-              const fb.Int64Reader().vTableGet(buffer, rootOffset, 20, 0);
-          object.to.attach(store);
-          return object;
-        }),
-    User: EntityDefinition<User>(
-        model: _entities[2],
-        toOneRelations: (User object) => [],
-        toManyRelations: (User object) => {
-              RelInfo<User>.toMany(2, object.id): object.friends,
-              RelInfo<User>.toMany(5, object.id): object.messages,
-              RelInfo<User>.toMany(6, object.id): object.groupMessages
-            },
-        getId: (User object) => object.id,
-        setId: (User object, int id) {
-          object.id = id;
-        },
-        objectToFB: (User object, fb.Builder fbb) {
-          final usernameOffset = fbb.writeString(object.username);
-          final bioOffset =
-              object.bio == null ? null : fbb.writeString(object.bio!);
-          final phoneOffset =
-              object.phone == null ? null : fbb.writeString(object.phone!);
-          final avatarOffset =
-              object.avatar == null ? null : fbb.writeString(object.avatar!);
-          fbb.startTable(10);
-          fbb.addInt64(0, object.id);
-          fbb.addOffset(2, usernameOffset);
-          fbb.addBool(3, object.isDND);
-          fbb.addBool(4, object.isStick);
-          fbb.addBool(5, object.isSpecialAttention);
-          fbb.addOffset(6, bioOffset);
-          fbb.addOffset(7, phoneOffset);
-          fbb.addOffset(8, avatarOffset);
-          fbb.finish(fbb.endTable());
-          return object.id;
-        },
-        objectFromFB: (Store store, ByteData fbData) {
-          final buffer = fb.BufferContext(fbData);
-          final rootOffset = buffer.derefObject(0);
-
-          final object = User(
-              const fb.StringReader().vTableGet(buffer, rootOffset, 8, ''),
-              bio: const fb.StringReader()
-                  .vTableGetNullable(buffer, rootOffset, 16),
-              phone: const fb.StringReader()
-                  .vTableGetNullable(buffer, rootOffset, 18),
-              avatar: const fb.StringReader()
-                  .vTableGetNullable(buffer, rootOffset, 20))
-            ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0)
-            ..isDND =
-                const fb.BoolReader().vTableGet(buffer, rootOffset, 10, false)
-            ..isStick =
-                const fb.BoolReader().vTableGet(buffer, rootOffset, 12, false)
-            ..isSpecialAttention =
-                const fb.BoolReader().vTableGet(buffer, rootOffset, 14, false);
-          InternalToManyAccess.setRelInfo(object.friends, store,
-              RelInfo<User>.toMany(2, object.id), store.box<User>());
-          InternalToManyAccess.setRelInfo(object.messages, store,
-              RelInfo<User>.toMany(5, object.id), store.box<User>());
-          InternalToManyAccess.setRelInfo(object.groupMessages, store,
-              RelInfo<User>.toMany(6, object.id), store.box<User>());
-          return object;
-        }),
-    Group: EntityDefinition<Group>(
-        model: _entities[3],
-        toOneRelations: (Group object) => [],
-        toManyRelations: (Group object) => {
-              RelInfo<Group>.toMany(3, object.id): object.members,
-              RelInfo<Group>.toMany(4, object.id): object.messages
-            },
-        getId: (Group object) => object.id,
-        setId: (Group object, int id) {
-          object.id = id;
-        },
-        objectToFB: (Group object, fb.Builder fbb) {
-          fbb.startTable(2);
-          fbb.addInt64(0, object.id);
-          fbb.finish(fbb.endTable());
-          return object.id;
-        },
-        objectFromFB: (Store store, ByteData fbData) {
-          final buffer = fb.BufferContext(fbData);
-          final rootOffset = buffer.derefObject(0);
-
-          final object = Group()
-            ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0);
-          InternalToManyAccess.setRelInfo(object.members, store,
-              RelInfo<Group>.toMany(3, object.id), store.box<Group>());
-          InternalToManyAccess.setRelInfo(object.messages, store,
-              RelInfo<Group>.toMany(4, object.id), store.box<Group>());
-          return object;
-        }),
-    GroupMessage: EntityDefinition<GroupMessage>(
-        model: _entities[4],
-        toOneRelations: (GroupMessage object) => [object.user, object.group],
-        toManyRelations: (GroupMessage object) => {},
-        getId: (GroupMessage object) => object.id,
-        setId: (GroupMessage object, int id) {
-          object.id = id;
-        },
-        objectToFB: (GroupMessage object, fb.Builder fbb) {
-          final plaintextOffset = fbb.writeString(object.plaintext);
-          fbb.startTable(10);
-          fbb.addInt64(0, object.id);
-          fbb.addInt64(6, object.user.targetId);
-          fbb.addInt64(7, object.group.targetId);
-          fbb.addOffset(8, plaintextOffset);
-          fbb.finish(fbb.endTable());
-          return object.id;
-        },
-        objectFromFB: (Store store, ByteData fbData) {
-          final buffer = fb.BufferContext(fbData);
-          final rootOffset = buffer.derefObject(0);
-
-          final object = GroupMessage()
-            ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0)
-            ..plaintext =
-                const fb.StringReader().vTableGet(buffer, rootOffset, 20, '');
-          object.user.targetId =
-              const fb.Int64Reader().vTableGet(buffer, rootOffset, 16, 0);
-          object.user.attach(store);
-          object.group.targetId =
-              const fb.Int64Reader().vTableGet(buffer, rootOffset, 18, 0);
-          object.group.attach(store);
-          return object;
-        }),
-    FriendShip: EntityDefinition<FriendShip>(
-        model: _entities[5],
-        toOneRelations: (FriendShip object) => [object.user0, object.user1],
-        toManyRelations: (FriendShip object) =>
-            {RelInfo<FriendShip>.toMany(7, object.id): object.messages},
-        getId: (FriendShip object) => object.id,
-        setId: (FriendShip object, int id) {
-          object.id = id;
-        },
-        objectToFB: (FriendShip object, fb.Builder fbb) {
-          fbb.startTable(6);
-          fbb.addInt64(0, object.id);
-          fbb.addInt64(3, object.user0.targetId);
-          fbb.addInt64(4, object.user1.targetId);
-          fbb.finish(fbb.endTable());
-          return object.id;
-        },
-        objectFromFB: (Store store, ByteData fbData) {
-          final buffer = fb.BufferContext(fbData);
-          final rootOffset = buffer.derefObject(0);
-
-          final object = FriendShip()
-            ..id = const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0);
-          object.user0.targetId =
-              const fb.Int64Reader().vTableGet(buffer, rootOffset, 10, 0);
-          object.user0.attach(store);
-          object.user1.targetId =
-              const fb.Int64Reader().vTableGet(buffer, rootOffset, 12, 0);
-          object.user1.attach(store);
-          InternalToManyAccess.setRelInfo(
-              object.messages,
-              store,
-              RelInfo<FriendShip>.toMany(7, object.id),
-              store.box<FriendShip>());
-          return object;
-        })
-  };
-
-  return ModelDefinition(model, bindings);
-}
-
-/// [Profile] entity fields to define ObjectBox queries.
-class Profile_ {
-  /// see [Profile.id]
-  static final id = QueryIntegerProperty<Profile>(_entities[0].properties[0]);
-
-  /// see [Profile.theme]
-  static final theme =
-      QueryIntegerProperty<Profile>(_entities[0].properties[1]);
-
-  /// see [Profile.isLogin]
-  static final isLogin =
-      QueryBooleanProperty<Profile>(_entities[0].properties[2]);
-
-  /// see [Profile.isLogout]
-  static final isLogout =
-      QueryBooleanProperty<Profile>(_entities[0].properties[3]);
-}
-
-/// [Message] entity fields to define ObjectBox queries.
-class Message_ {
-  /// see [Message.id]
-  static final id = QueryIntegerProperty<Message>(_entities[1].properties[0]);
-
-  /// see [Message.from]
-  static final from =
-      QueryRelationToOne<Message, User>(_entities[1].properties[1]);
-
-  /// see [Message.to]
-  static final to =
-      QueryRelationToOne<Message, User>(_entities[1].properties[2]);
-
-  /// see [Message.plaintext]
-  static final plaintext =
-      QueryStringProperty<Message>(_entities[1].properties[3]);
-}
-
-/// [User] entity fields to define ObjectBox queries.
-class User_ {
-  /// see [User.id]
-  static final id = QueryIntegerProperty<User>(_entities[2].properties[0]);
-
-  /// see [User.username]
-  static final username = QueryStringProperty<User>(_entities[2].properties[1]);
-
-  /// see [User.isDND]
-  static final isDND = QueryBooleanProperty<User>(_entities[2].properties[2]);
-
-  /// see [User.isStick]
-  static final isStick = QueryBooleanProperty<User>(_entities[2].properties[3]);
-
-  /// see [User.isSpecialAttention]
-  static final isSpecialAttention =
-      QueryBooleanProperty<User>(_entities[2].properties[4]);
-
-  /// see [User.bio]
-  static final bio = QueryStringProperty<User>(_entities[2].properties[5]);
-
-  /// see [User.phone]
-  static final phone = QueryStringProperty<User>(_entities[2].properties[6]);
-
-  /// see [User.avatar]
-  static final avatar = QueryStringProperty<User>(_entities[2].properties[7]);
-
-  /// see [User.friends]
-  static final friends =
-      QueryRelationToMany<User, User>(_entities[2].relations[0]);
-
-  /// see [User.messages]
-  static final messages =
-      QueryRelationToMany<User, Message>(_entities[2].relations[1]);
-
-  /// see [User.groupMessages]
-  static final groupMessages =
-      QueryRelationToMany<User, GroupMessage>(_entities[2].relations[2]);
-}
-
-/// [Group] entity fields to define ObjectBox queries.
-class Group_ {
-  /// see [Group.id]
-  static final id = QueryIntegerProperty<Group>(_entities[3].properties[0]);
-
-  /// see [Group.members]
-  static final members =
-      QueryRelationToMany<Group, User>(_entities[3].relations[0]);
-
-  /// see [Group.messages]
-  static final messages =
-      QueryRelationToMany<Group, GroupMessage>(_entities[3].relations[1]);
-}
-
-/// [GroupMessage] entity fields to define ObjectBox queries.
-class GroupMessage_ {
-  /// see [GroupMessage.id]
-  static final id =
-      QueryIntegerProperty<GroupMessage>(_entities[4].properties[0]);
-
-  /// see [GroupMessage.user]
-  static final user =
-      QueryRelationToOne<GroupMessage, User>(_entities[4].properties[1]);
-
-  /// see [GroupMessage.group]
-  static final group =
-      QueryRelationToOne<GroupMessage, Group>(_entities[4].properties[2]);
-
-  /// see [GroupMessage.plaintext]
-  static final plaintext =
-      QueryStringProperty<GroupMessage>(_entities[4].properties[3]);
-}
-
-/// [FriendShip] entity fields to define ObjectBox queries.
-class FriendShip_ {
-  /// see [FriendShip.id]
-  static final id =
-      QueryIntegerProperty<FriendShip>(_entities[5].properties[0]);
-
-  /// see [FriendShip.user0]
-  static final user0 =
-      QueryRelationToOne<FriendShip, User>(_entities[5].properties[1]);
-
-  /// see [FriendShip.user1]
-  static final user1 =
-      QueryRelationToOne<FriendShip, User>(_entities[5].properties[2]);
-
-  /// see [FriendShip.messages]
-  static final messages =
-      QueryRelationToMany<FriendShip, Message>(_entities[5].relations[0]);
-}

+ 0 - 1
lib/presenter/contact_list.dart

@@ -9,7 +9,6 @@ import 'package:flutter/material.dart';
 import 'package:lpinyin/lpinyin.dart';
 import 'package:e2ee_chat/common/api.dart';
 
-import '../objectbox.g.dart';
 import 'login.dart';
 
 class ContactListPresenter extends ChangeNotifier {

+ 0 - 2
lib/presenter/friend_request.dart

@@ -9,10 +9,8 @@ import 'package:e2ee_chat/model/contact_info.dart';
 import 'package:e2ee_chat/model/friendship.dart';
 import 'package:e2ee_chat/model/message.dart';
 import 'package:e2ee_chat/model/user.dart';
-import 'package:e2ee_chat/objectbox.g.dart';
 import 'package:e2ee_chat/presenter/login.dart';
 import 'package:flutter/material.dart';
-import 'package:objectbox/objectbox.dart';
 import 'package:rxdart/rxdart.dart';
 
 import 'chat_list.dart';

+ 2 - 2
lib/presenter/locale.dart

@@ -5,9 +5,9 @@ import 'profile.dart';
 class LocaleModel extends ProfilePresenter {
   LocaleModel();
 
-  Locale? get locale => profile.locale;
+  Locale get locale => profile.locale;
 
-  set locale(Locale? value) {
+  set locale(Locale value) {
     profile.locale = value;
     notifyListeners();
   }

+ 0 - 15
lib/presenter/login.dart

@@ -7,7 +7,6 @@ import 'package:e2ee_chat/common/global.dart';
 import 'package:e2ee_chat/common/api.dart';
 import '../model/user.dart';
 
-import '../objectbox.g.dart';
 import 'profile.dart';
 
 /*
@@ -43,20 +42,6 @@ class LoginPresenter extends ProfilePresenter {
 
   User? get user => profile.user;
 
-  @Transient()
-  Future<Key?> get secretKey async {
-    if (user == null) return null;
-    final storage = FlutterSecureStorage();
-    String? _base64 = await storage.read(key: _keyKey);
-    if (_base64 == null) {
-      _base64 = Key.fromSecureRandom(256).base64;
-      await storage.write(key: _keyKey, value: _base64);
-    }
-    return Key.fromBase64(_base64);
-  }
-
-  String get _keyKey => "e2ee_chat secret key of ${user!.username}";
-
   Future<bool> login({String? username, String? password}) async {
     debug('UserModel login begin');
     if (username != null) {

+ 0 - 1
lib/presenter/profile.dart

@@ -3,7 +3,6 @@ import 'package:e2ee_chat/model/user.dart';
 import 'package:flutter/cupertino.dart';
 
 import '../common/global.dart';
-import '../objectbox.g.dart';
 
 class ProfilePresenter extends ChangeNotifier {
   Profile get profile => Global.profile;

+ 29 - 79
lib/presenter/user_chat.dart

@@ -1,16 +1,13 @@
 import 'dart:async';
 import 'dart:convert';
+import 'dart:io';
 
 import 'package:dash_chat/dash_chat.dart';
 import 'package:e2ee_chat/common/api.dart';
 import 'package:e2ee_chat/common/global.dart';
-import 'package:e2ee_chat/model/friendship.dart';
 import 'package:e2ee_chat/model/message.dart';
 import 'package:e2ee_chat/model/user.dart';
-import 'package:e2ee_chat/objectbox.g.dart';
 import 'package:e2ee_chat/presenter/login.dart';
-import 'package:flutter/material.dart';
-import 'package:objectbox/objectbox.dart';
 
 import 'chat_list.dart';
 
@@ -22,31 +19,23 @@ class UserChatPresenter extends ChatListPresenter {
   User? get from => LoginPresenter().user;
   User? to;
 
-  FriendShip get friendShip => FriendShip()
-    ..user0.target = from
-    ..user1.target = to;
-
-  ToMany<Message> get messages => friendShip.messages;
-
   List<ChatMessage>? _chatMessages;
   List<ChatMessage> get chatMessages => _chatMessages ?? [];
 
   bool _disposed = false;
   Future<void>? _listener;
 
-
   @override
   void dispose() {
     _disposed = true;
     _listener?.then((e) => super.dispose()) ?? super.dispose();
   }
 
-
   Future<void> _listenUserChat() async {
     while (!_disposed) {
       if (to != null) {
         if (_chatMessages == null) {
-            debug("init chatMessages");
+          debug("init chatMessages");
           _chatMessages = await retrieveAllChatMessages();
           notifyListeners();
         } else {
@@ -64,7 +53,10 @@ class UserChatPresenter extends ChatListPresenter {
       if (_list != null) {
         debug("flush chat message");
         for (final i in _list) {
-          chatMessages.add(chatMessageFromMessagePackage(i));
+          final _chatMessage = await chatMessageFromMessage(i);
+          if (_chatMessage != null) {
+            chatMessages.add(_chatMessage);
+          }
         }
         notifyListeners();
       }
@@ -72,23 +64,20 @@ class UserChatPresenter extends ChatListPresenter {
     // messages.forEach((message) => list.add(message.chatMessage));
   }
 
-  Future<ChatMessage> chatMessageFromMessagePackage(String encText) async {
-    Key? key = await LoginPresenter().secretKey;
-    String plaintext = ;
-    ChatMessage? _message;
+  Future<ChatMessage?> chatMessageFromMessage(String json) async {
+    String? username = from?.username;
+    ChatMessage? _chatMessage;
     try {
-      _message = ChatMessage.fromJson(jsonDecode(encText));
+      _chatMessage = ChatMessage.fromJson(jsonDecode(json));
     } catch (e) {
       try {
-
-        _message = ChatMessage.fromJson()
+        final _message = Message.fromJson(jsonDecode(json));
+        _chatMessage = await _message.chatMessage;
       } catch (e) {
-
+        debug('chatMessageFromMessagePackage error: e');
       }
     }
-    debug('plaintext: $encText');
-
-    return ChatMessage.fromJson(jsonDecode(plaintext));
+    return _chatMessage;
   }
 
   Future<List<ChatMessage>> retrieveAllChatMessages() async {
@@ -99,7 +88,10 @@ class UserChatPresenter extends ChatListPresenter {
       List<String>? _list = await Api().getFilterMessages(_to.username);
       if (_list != null) {
         for (final i in _list) {
-          list.add(chatMessageFromMessagePackage(i));
+          final _chatMessage = await chatMessageFromMessage(i);
+          if (_chatMessage != null) {
+            list.add(_chatMessage);
+          }
         }
       }
     }
@@ -112,63 +104,21 @@ class UserChatPresenter extends ChatListPresenter {
     bool _result = true;
     chatMessages.add(chatMessage);
     notifyListeners();
-    try {
-      final plaintext = json.encode(chatMessage);
-      var message = Message();
-      message.from.target = from!;
-      message.to.target = to!;
-      message.plaintext = plaintext;
-      _result = await Api().sendMessage(to!.username, json.encode(chatMessage));
-    } catch (e) {
-      debug(e);
-      _result = false;
+    if (from != null && to != null) {
+      try {
+        String plaintext = jsonEncode(chatMessage.toJson());
+        // TODO: encrypt
+        String publicKey = "";
+        final message = Message.encrypt(from!.username, to!.username, plaintext, publicKey);
+        _result = await Api().sendMessage(to!.username, jsonEncode(message.toJson()));
+      } catch (e) {
+        debug(e);
+        _result = false;
+      }
     }
     if (!_result) {
       debug('user chat presenter send msg failed');
     }
     return _result;
   }
-
-  /// 消息体
-  Message? get lastMessage {
-    Message? message;
-    try {
-      message = messages.last;
-    } catch (e) {
-      debug("no message");
-    }
-    return message;
-  }
-
-  /// 未读数量
-  int get unReadCount {
-    // TODO: 未读消息数量
-    return 0;
-  }
-
-  get chatName => to?.username;
-
-  /// 单聊
-  get isSingle => true;
-
-  /// 群聊信息
-  get isGroup => false;
-
-  /// 消息免打扰
-  get isDND => to?.isDND;
-
-  /// 是否为置顶
-  get isStick => to?.isStick;
-
-  /// 特别关注
-  get isSpecialAttention => to?.isSpecialAttention;
-
-  // TODO: 是否 @ 你
-  get isAtYou => false;
-
-  // TODO: 是否 @ 全部
-  get isAtAll => false;
-
-  // TODO: user avatar
-  get avatar => Global.defaultAvatar;
 }

+ 71 - 71
lib/view/chat_list.dart

@@ -1,71 +1,71 @@
-import 'package:e2ee_chat/common/global.dart';
-import 'package:e2ee_chat/presenter/chat_list.dart';
-import 'package:e2ee_chat/widgets/chat_list_item.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_slidable/flutter_slidable.dart';
-import 'package:provider/provider.dart';
-
-class ChatList extends StatefulWidget {
-  @override
-  _ChatListState createState() => _ChatListState();
-}
-
-class _ChatListState extends State<ChatList> {
-  @override
-  Widget build(BuildContext context) {
-    return ChangeNotifierProvider<ChatListPresenter>(
-      create: (context) {
-        return ChatListPresenter();
-      },
-      child: Builder(
-        builder: (context) {
-          final provider = Provider.of<ChatListPresenter>(context);
-          final list = provider.chatList;
-          return RefreshIndicator(
-              child: ListView.builder(
-                  itemCount: list.length,
-                  itemBuilder: (context, index) {
-                    final _item = list[index];
-                    return Slidable(
-                      actionPane: SlidableDrawerActionPane(),
-                      actionExtentRatio: 0.25,
-                      secondaryActions: <Widget>[
-                        IconSlideAction(
-                          caption: '取消置顶',
-                          color: Colors.black45,
-                          icon: Icons.more_horiz,
-                          onTap: () {},
-                        ),
-                        IconSlideAction(
-                          caption: '删除',
-                          color: Colors.redAccent,
-                          icon: Icons.delete,
-                          onTap: () => {},
-                        ),
-                      ],
-                      child: Padding(
-                        padding: EdgeInsets.only(left: 36, bottom: 20, top: 20),
-                        child: Row(
-                          crossAxisAlignment: CrossAxisAlignment.start,
-                          children: <Widget>[
-                            Expanded(child: ChatListItem(_item)),
-                            _item.isStick
-                                ? Container(
-                                    width: 40,
-                                    height: 48,
-                                    margin: EdgeInsets.only(top: 10, right: 10),
-                                    child: Icon(Icons.star))
-                                : Padding(
-                                    padding: EdgeInsets.symmetric(horizontal: 24),
-                                  )
-                          ],
-                        ),
-                      ),
-                    );
-                  }),
-              onRefresh: () async {});
-        },
-      ),
-    );
-  }
-}
+// import 'package:e2ee_chat/common/global.dart';
+// import 'package:e2ee_chat/presenter/chat_list.dart';
+// import 'package:e2ee_chat/widgets/chat_list_item.dart';
+// import 'package:flutter/material.dart';
+// import 'package:flutter_slidable/flutter_slidable.dart';
+// import 'package:provider/provider.dart';
+//
+// class ChatList extends StatefulWidget {
+//   @override
+//   _ChatListState createState() => _ChatListState();
+// }
+//
+// class _ChatListState extends State<ChatList> {
+//   @override
+//   Widget build(BuildContext context) {
+//     return ChangeNotifierProvider<ChatListPresenter>(
+//       create: (context) {
+//         return ChatListPresenter();
+//       },
+//       child: Builder(
+//         builder: (context) {
+//           final provider = Provider.of<ChatListPresenter>(context);
+//           final list = provider.chatList;
+//           return RefreshIndicator(
+//               child: ListView.builder(
+//                   itemCount: list.length,
+//                   itemBuilder: (context, index) {
+//                     final _item = list[index];
+//                     return Slidable(
+//                       actionPane: SlidableDrawerActionPane(),
+//                       actionExtentRatio: 0.25,
+//                       secondaryActions: <Widget>[
+//                         IconSlideAction(
+//                           caption: '取消置顶',
+//                           color: Colors.black45,
+//                           icon: Icons.more_horiz,
+//                           onTap: () {},
+//                         ),
+//                         IconSlideAction(
+//                           caption: '删除',
+//                           color: Colors.redAccent,
+//                           icon: Icons.delete,
+//                           onTap: () => {},
+//                         ),
+//                       ],
+//                       child: Padding(
+//                         padding: EdgeInsets.only(left: 36, bottom: 20, top: 20),
+//                         child: Row(
+//                           crossAxisAlignment: CrossAxisAlignment.start,
+//                           children: <Widget>[
+//                             Expanded(child: ChatListItem(_item)),
+//                             _item.isStick
+//                                 ? Container(
+//                                     width: 40,
+//                                     height: 48,
+//                                     margin: EdgeInsets.only(top: 10, right: 10),
+//                                     child: Icon(Icons.star))
+//                                 : Padding(
+//                                     padding: EdgeInsets.symmetric(horizontal: 24),
+//                                   )
+//                           ],
+//                         ),
+//                       ),
+//                     );
+//                   }),
+//               onRefresh: () async {});
+//         },
+//       ),
+//     );
+//   }
+// }

+ 1 - 1
lib/view/home.dart

@@ -72,7 +72,7 @@ class _HomeRouteState extends State<HomeRoute> {
   Widget _buildBody() {
     switch (_index) {
       case 0:
-        return ChatList();
+        return ContactListView();
       case 1:
         return ContactListView();
       case 2:

+ 105 - 105
lib/widgets/chat_list_item.dart

@@ -1,105 +1,105 @@
-import 'package:e2ee_chat/common/global.dart';
-import 'package:e2ee_chat/presenter/chat_list.dart';
-import 'package:e2ee_chat/presenter/user_chat.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_slidable/flutter_slidable.dart';
-import 'package:provider/provider.dart';
-
-class ChatListItem extends StatelessWidget {
-  final UserChatPresenter model;
-
-  ChatListItem(this.model);
-
-  @override
-  Widget build(BuildContext context) {
-    final message = model.lastMessage;
-    return Row(
-      mainAxisAlignment: MainAxisAlignment.spaceBetween,
-      children: <Widget>[
-        model.avatar ?? Global.defaultAvatar,
-        Expanded(
-          child: Column(
-            children: <Widget>[
-              Padding(
-                padding: EdgeInsets.symmetric(vertical: 8),
-                child: Row(
-                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                  children: <Widget>[
-                    Expanded(
-                      child: Text(
-                        model.chatName,
-                        style: TextStyle(fontSize: 34),
-                        overflow: TextOverflow.ellipsis,
-                      ),
-                    ),
-                    Text(
-                      _formatDate(),
-                      style: TextStyle(fontSize: 26),
-                      overflow: TextOverflow.ellipsis,
-                    ),
-                  ],
-                ),
-              ),
-              Row(
-                mainAxisAlignment: MainAxisAlignment.spaceBetween,
-                children: <Widget>[
-                  Expanded(
-                    child: RichText(
-                      text: TextSpan(children: [
-                        TextSpan(
-                          text: model.isAtYou ? "[@你]" : "",
-                          style: TextStyle(fontSize: 28),
-                        ),
-                        TextSpan(
-                          text: model.isSpecialAttention ? "[特别关注]" : "",
-                          style: TextStyle(fontSize: 28),
-                        ),
-                        TextSpan(
-                          text: model.isAtAll ? "[@所有人]" : "",
-                          style: TextStyle(fontSize: 28),
-                        ),
-                        TextSpan(
-                          text: model.lastMessage?.plaintext ?? "",
-                          style: TextStyle(fontSize: 28),
-                        )
-                      ]),
-                      overflow: TextOverflow.ellipsis,
-                    ),
-                  ),
-                  (model.unReadCount > 0 && !model.isDND)
-                      ? Container(
-                      width: 32,
-                      height: 32,
-                      alignment: Alignment.center,
-                      decoration: BoxDecoration(borderRadius: BorderRadius.circular(20)),
-                      child: Text(
-                        model.unReadCount.toString(),
-                        style: TextStyle(color: Colors.white, fontSize: 26),
-                      ))
-                      : Container(),
-                  model.isDND
-                      ? Row(
-                    children: <Widget>[
-                      Icon(Icons.visibility_off),
-                      model.unReadCount > 0
-                          ? Icon(
-                        Icons.chat_bubble,
-                        color: Colors.red,
-                      ) // TODO: 小红点
-                          : Container()
-                    ],
-                  )
-                      : Container()
-                ],
-              )
-            ],
-          ),
-        )
-      ],
-    );
-  }
-
-  String _formatDate() {
-    return "1234";
-  }
-}
+// import 'package:e2ee_chat/common/global.dart';
+// import 'package:e2ee_chat/presenter/chat_list.dart';
+// import 'package:e2ee_chat/presenter/user_chat.dart';
+// import 'package:flutter/material.dart';
+// import 'package:flutter_slidable/flutter_slidable.dart';
+// import 'package:provider/provider.dart';
+//
+// class ChatListItem extends StatelessWidget {
+//   final UserChatPresenter model;
+//
+//   ChatListItem(this.model);
+//
+//   @override
+//   Widget build(BuildContext context) {
+//     final message = model.lastMessage;
+//     return Row(
+//       mainAxisAlignment: MainAxisAlignment.spaceBetween,
+//       children: <Widget>[
+//         model.avatar ?? Global.defaultAvatar,
+//         Expanded(
+//           child: Column(
+//             children: <Widget>[
+//               Padding(
+//                 padding: EdgeInsets.symmetric(vertical: 8),
+//                 child: Row(
+//                   mainAxisAlignment: MainAxisAlignment.spaceBetween,
+//                   children: <Widget>[
+//                     Expanded(
+//                       child: Text(
+//                         model.chatName,
+//                         style: TextStyle(fontSize: 34),
+//                         overflow: TextOverflow.ellipsis,
+//                       ),
+//                     ),
+//                     Text(
+//                       _formatDate(),
+//                       style: TextStyle(fontSize: 26),
+//                       overflow: TextOverflow.ellipsis,
+//                     ),
+//                   ],
+//                 ),
+//               ),
+//               Row(
+//                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
+//                 children: <Widget>[
+//                   Expanded(
+//                     child: RichText(
+//                       text: TextSpan(children: [
+//                         TextSpan(
+//                           text: model.isAtYou ? "[@你]" : "",
+//                           style: TextStyle(fontSize: 28),
+//                         ),
+//                         TextSpan(
+//                           text: model.isSpecialAttention ? "[特别关注]" : "",
+//                           style: TextStyle(fontSize: 28),
+//                         ),
+//                         TextSpan(
+//                           text: model.isAtAll ? "[@所有人]" : "",
+//                           style: TextStyle(fontSize: 28),
+//                         ),
+//                         TextSpan(
+//                           text: model.lastMessage?.plaintext ?? "",
+//                           style: TextStyle(fontSize: 28),
+//                         )
+//                       ]),
+//                       overflow: TextOverflow.ellipsis,
+//                     ),
+//                   ),
+//                   (model.unReadCount > 0 && !model.isDND)
+//                       ? Container(
+//                       width: 32,
+//                       height: 32,
+//                       alignment: Alignment.center,
+//                       decoration: BoxDecoration(borderRadius: BorderRadius.circular(20)),
+//                       child: Text(
+//                         model.unReadCount.toString(),
+//                         style: TextStyle(color: Colors.white, fontSize: 26),
+//                       ))
+//                       : Container(),
+//                   model.isDND
+//                       ? Row(
+//                     children: <Widget>[
+//                       Icon(Icons.visibility_off),
+//                       model.unReadCount > 0
+//                           ? Icon(
+//                         Icons.chat_bubble,
+//                         color: Colors.red,
+//                       ) // TODO: 小红点
+//                           : Container()
+//                     ],
+//                   )
+//                       : Container()
+//                 ],
+//               )
+//             ],
+//           ),
+//         )
+//       ],
+//     );
+//   }
+//
+//   String _formatDate() {
+//     return "1234";
+//   }
+// }

+ 51 - 23
pubspec.lock

@@ -364,6 +364,13 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "4.0.1"
+  json_serializable:
+    dependency: "direct main"
+    description:
+      name: json_serializable
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "4.1.3"
   logging:
     dependency: transitive
     description:
@@ -406,27 +413,6 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "1.0.0"
-  objectbox:
-    dependency: "direct main"
-    description:
-      name: objectbox
-      url: "https://pub.flutter-io.cn"
-    source: hosted
-    version: "1.1.1"
-  objectbox_flutter_libs:
-    dependency: "direct main"
-    description:
-      name: objectbox_flutter_libs
-      url: "https://pub.flutter-io.cn"
-    source: hosted
-    version: "1.1.1"
-  objectbox_generator:
-    dependency: "direct dev"
-    description:
-      name: objectbox_generator
-      url: "https://pub.flutter-io.cn"
-    source: hosted
-    version: "1.1.1"
   package_config:
     dependency: transitive
     description:
@@ -442,7 +428,7 @@ packages:
     source: hosted
     version: "1.8.0"
   path_provider:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: path_provider
       url: "https://pub.flutter-io.cn"
@@ -574,6 +560,48 @@ packages:
       url: "https://pub.flutter-io.cn"
     source: hosted
     version: "0.2.0-nullsafety.0"
+  shared_preferences:
+    dependency: "direct main"
+    description:
+      name: shared_preferences
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.6"
+  shared_preferences_linux:
+    dependency: transitive
+    description:
+      name: shared_preferences_linux
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.0"
+  shared_preferences_macos:
+    dependency: transitive
+    description:
+      name: shared_preferences_macos
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.0"
+  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.0"
+  shared_preferences_windows:
+    dependency: transitive
+    description:
+      name: shared_preferences_windows
+      url: "https://pub.flutter-io.cn"
+    source: hosted
+    version: "2.0.0"
   shelf:
     dependency: transitive
     description:
@@ -721,4 +749,4 @@ packages:
     version: "3.1.0"
 sdks:
   dart: ">=2.13.0 <3.0.0"
-  flutter: ">=2.0.0"
+  flutter: ">=1.26.0-17.6.pre"

+ 3 - 5
pubspec.yaml

@@ -28,14 +28,13 @@ dependencies:
   provider: ^5.0.0
   rxdart: ^0.27.1
 
+  shared_preferences: ^2.0.6
   flutter_secure_storage: ^4.2.0
   crypto: ^3.0.1
   encrypt: ^5.0.0
+  path_provider: ^2.0.2
 
-  objectbox: ^1.0.0
-  objectbox_flutter_libs: any
-  # for ObjectBox Sync use this dependency instead:
-  # objectbox_sync_flutter_libs: any
+  json_serializable: ^4.1.3
 
   dio: ^4.0.0
   dio_cookie_manager: ^2.0.0
@@ -62,7 +61,6 @@ dev_dependencies:
   flutter_test:
     sdk: flutter
   build_runner: ^2.0.5
-  objectbox_generator: any
 
 # For information on the generic Dart part of this file, see the
 # following page: https://dart.dev/tools/pub/pubspec