فهرست منبع

[new]增加getit框架

zk 10 ماه پیش
والد
کامیت
536b4cc301
36فایلهای تغییر یافته به همراه1209 افزوده شده و 74 حذف شده
  1. 141 0
      lib/base/base_request.dart
  2. 63 0
      lib/base/base_request.g.dart
  3. 16 0
      lib/base/base_response.dart
  4. 39 0
      lib/base/base_response.g.dart
  5. 0 30
      lib/base/get_it.config.dart
  6. 16 0
      lib/data/api/atmob_api.dart
  7. 90 0
      lib/data/api/atmob_api.g.dart
  8. 35 0
      lib/data/api/interceptor/stream_dio_log_interceptor.dart
  9. 12 0
      lib/data/api/request/send_code_request.dart
  10. 67 0
      lib/data/api/request/send_code_request.g.dart
  11. 34 0
      lib/data/bean/location_info.dart
  12. 51 0
      lib/data/bean/user_info.dart
  13. 50 0
      lib/data/consts/constants.dart
  14. 14 1
      lib/data/repositories/account_repository.dart
  15. 168 0
      lib/device/atmob_platform_info.dart
  16. 13 0
      lib/device/device_info_util.dart
  17. 19 0
      lib/device/platform_android_info.dart
  18. 32 0
      lib/device/platform_ios_info.dart
  19. 47 0
      lib/di/get_it.config.dart
  20. 4 4
      lib/base/get_it.dart
  21. 10 20
      lib/di/network_module.dart
  22. 42 1
      lib/main.dart
  23. 25 0
      lib/module/add_friend/add_friend_dialog_controller.dart
  24. 5 4
      lib/module/friend/add_friend/add_friend_view.dart
  25. 0 3
      lib/module/friend/add_friend/add_friend_dialog_controller.dart
  26. 9 1
      lib/module/main/main_controller.dart
  27. 9 4
      lib/module/main/main_page.dart
  28. 2 0
      lib/module/splash/splash_controller.dart
  29. 6 5
      lib/router/app_pages.dart
  30. 23 0
      lib/utils/app_info_util.dart
  31. 29 0
      lib/utils/atmob_log.dart
  32. 34 0
      lib/utils/http_handler.dart
  33. 52 0
      lib/utils/mmkv_util.dart
  34. 23 0
      lib/utils/toast_util.dart
  35. 24 0
      pubspec.lock
  36. 5 1
      pubspec.yaml

+ 141 - 0
lib/base/base_request.dart

@@ -0,0 +1,141 @@
+import 'dart:io';
+
+import 'package:flutter/cupertino.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+import '../device/atmob_platform_info.dart';
+import '../utils/app_info_util.dart';
+
+part 'base_request.g.dart';
+
+@JsonSerializable()
+class BaseRequest {
+  /// 平台类型: 1-Android 2-iOS 3-移动H5 4-PC_WEB 5-微信小程序 6-微信小游戏
+  /// 7-微信公众号 8-抖音小程序 9-抖音小游戏 10-鸿蒙APP
+  @JsonKey(name: "appPlatform")
+  late int appPlatform = 0;
+
+  /// 操作系统:android、ios、mac、windows、linux、harmony
+  @JsonKey(name: "os")
+  late String os = "unknown";
+  @JsonKey(name: "osVersion")
+  late String osVersion;
+
+  /// 包信息
+  @JsonKey(name: "packageName")
+  String? packageName;
+  @JsonKey(name: "appVersionName")
+  String? appVersionName;
+  @JsonKey(name: "appVersionCode")
+  int? appVersionCode;
+
+  /// 渠道信息, iOS没有渠道信息, Android通过渠道包工具获取
+  @JsonKey(name: "channelName")
+  String? channelName;
+  @JsonKey(name: "appId")
+  int? appId;
+  @JsonKey(name: "tgPlatform")
+  int? tgPlatform;
+
+  /// 设备信息
+  /// Android特有
+  @JsonKey(name: "oaid")
+  String? oaid;
+  @JsonKey(name: "aaid")
+  String? aaid;
+  @JsonKey(name: "androidId")
+  String? androidId;
+  @JsonKey(name: "imei")
+  String? imei;
+  @JsonKey(name: "simImei0")
+  String? simImei0;
+  @JsonKey(name: "simImei1")
+  String? simImei1;
+  @JsonKey(name: "mac")
+  String? mac;
+
+  /// iOS特有
+  @JsonKey(name: "idfa")
+  String? idfa;
+  @JsonKey(name: "idfv")
+  String? idfv;
+
+  /// 公共设备信息
+  @JsonKey(name: "machineId")
+  String? machineId; //给web使用
+  @JsonKey(name: "brand")
+  String? brand;
+  @JsonKey(name: "model")
+  String? model;
+  @JsonKey(name: "wifiName")
+  String? wifiName;
+
+  /// 地理位置信息
+  @JsonKey(name: "region")
+  String? region;
+  @JsonKey(name: "locLng")
+  double? locLng;
+  @JsonKey(name: "locLat")
+  double? locLat;
+
+  BaseRequest() {
+    initPlatformOS();
+    initPackageInfo();
+    initChannelInfo();
+    initDeviceInfo();
+  }
+
+  Map<String, dynamic> toJson() => _$BaseRequestToJson(this);
+
+  void initPlatformOS() {
+    if (Platform.isAndroid) {
+      appPlatform = 1;
+      os = "android";
+    } else if (Platform.isIOS) {
+      appPlatform = 2;
+      os = "ios";
+    } else if (Platform.isMacOS) {
+      os = "mac";
+    } else if (Platform.isWindows) {
+      os = "windows";
+    } else if (Platform.isLinux) {
+      os = "linux";
+    } else if (Platform.isFuchsia) {
+      os = "fuchsia";
+    }
+    osVersion = Platform.operatingSystemVersion;
+
+    debugPrint("os: $os, osVersion: $osVersion");
+  }
+
+  void initPackageInfo() {
+    packageName = appInfoUtil.packageName;
+    appVersionName = appInfoUtil.appVersionName;
+    appVersionCode = appInfoUtil.appVersionCode;
+  }
+
+  void initChannelInfo() {
+    channelName = atmobPlatformInfo.channelName;
+    appId = atmobPlatformInfo.appId;
+    tgPlatform = atmobPlatformInfo.tgPlatform;
+  }
+
+  void initDeviceInfo() {
+    oaid = atmobPlatformInfo.oaid;
+    aaid = atmobPlatformInfo.aaid;
+    androidId = atmobPlatformInfo.androidId;
+    imei = atmobPlatformInfo.imei;
+    simImei0 = atmobPlatformInfo.simImei0;
+    simImei1 = atmobPlatformInfo.simImei1;
+    mac = atmobPlatformInfo.mac;
+    idfa = atmobPlatformInfo.idfa;
+    idfv = atmobPlatformInfo.idfv;
+    machineId = atmobPlatformInfo.machineId;
+    brand = atmobPlatformInfo.brand;
+    model = atmobPlatformInfo.model;
+    wifiName = atmobPlatformInfo.wifiName;
+    region = atmobPlatformInfo.region;
+    locLng = atmobPlatformInfo.locLng;
+    locLat = atmobPlatformInfo.locLat;
+  }
+}

+ 63 - 0
lib/base/base_request.g.dart

@@ -0,0 +1,63 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'base_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+BaseRequest _$BaseRequestFromJson(Map<String, dynamic> json) => BaseRequest()
+  ..appPlatform = (json['appPlatform'] as num).toInt()
+  ..os = json['os'] as String
+  ..osVersion = json['osVersion'] as String
+  ..packageName = json['packageName'] as String?
+  ..appVersionName = json['appVersionName'] as String?
+  ..appVersionCode = (json['appVersionCode'] as num?)?.toInt()
+  ..channelName = json['channelName'] as String?
+  ..appId = (json['appId'] as num?)?.toInt()
+  ..tgPlatform = (json['tgPlatform'] as num?)?.toInt()
+  ..oaid = json['oaid'] as String?
+  ..aaid = json['aaid'] as String?
+  ..androidId = json['androidId'] as String?
+  ..imei = json['imei'] as String?
+  ..simImei0 = json['simImei0'] as String?
+  ..simImei1 = json['simImei1'] as String?
+  ..mac = json['mac'] as String?
+  ..idfa = json['idfa'] as String?
+  ..idfv = json['idfv'] as String?
+  ..machineId = json['machineId'] as String?
+  ..brand = json['brand'] as String?
+  ..model = json['model'] as String?
+  ..wifiName = json['wifiName'] as String?
+  ..region = json['region'] as String?
+  ..locLng = (json['locLng'] as num?)?.toDouble()
+  ..locLat = (json['locLat'] as num?)?.toDouble();
+
+Map<String, dynamic> _$BaseRequestToJson(BaseRequest instance) =>
+    <String, dynamic>{
+      'appPlatform': instance.appPlatform,
+      'os': instance.os,
+      'osVersion': instance.osVersion,
+      'packageName': instance.packageName,
+      'appVersionName': instance.appVersionName,
+      'appVersionCode': instance.appVersionCode,
+      'channelName': instance.channelName,
+      'appId': instance.appId,
+      'tgPlatform': instance.tgPlatform,
+      'oaid': instance.oaid,
+      'aaid': instance.aaid,
+      'androidId': instance.androidId,
+      'imei': instance.imei,
+      'simImei0': instance.simImei0,
+      'simImei1': instance.simImei1,
+      'mac': instance.mac,
+      'idfa': instance.idfa,
+      'idfv': instance.idfv,
+      'machineId': instance.machineId,
+      'brand': instance.brand,
+      'model': instance.model,
+      'wifiName': instance.wifiName,
+      'region': instance.region,
+      'locLng': instance.locLng,
+      'locLat': instance.locLat,
+    };

+ 16 - 0
lib/base/base_response.dart

@@ -0,0 +1,16 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'base_response.g.dart';
+
+@JsonSerializable(genericArgumentFactories: true)
+class BaseResponse<T> {
+  int? code;
+  String? message;
+  T? data;
+
+  BaseResponse(this.data, this.code, this.message);
+
+  factory BaseResponse.fromJson(
+          Map<String, dynamic> json, T Function(Object? json) fromJsonT) =>
+      _$BaseResponseFromJson(json, fromJsonT);
+}

+ 39 - 0
lib/base/base_response.g.dart

@@ -0,0 +1,39 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'base_response.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+BaseResponse<T> _$BaseResponseFromJson<T>(
+  Map<String, dynamic> json,
+  T Function(Object? json) fromJsonT,
+) =>
+    BaseResponse<T>(
+      _$nullableGenericFromJson(json['data'], fromJsonT),
+      (json['code'] as num?)?.toInt(),
+      json['message'] as String?,
+    );
+
+Map<String, dynamic> _$BaseResponseToJson<T>(
+  BaseResponse<T> instance,
+  Object? Function(T value) toJsonT,
+) =>
+    <String, dynamic>{
+      'code': instance.code,
+      'message': instance.message,
+      'data': _$nullableGenericToJson(instance.data, toJsonT),
+    };
+
+T? _$nullableGenericFromJson<T>(
+  Object? input,
+  T Function(Object? json) fromJson,
+) =>
+    input == null ? null : fromJson(input);
+
+Object? _$nullableGenericToJson<T>(
+  T? input,
+  Object? Function(T value) toJson,
+) =>
+    input == null ? null : toJson(input);

+ 0 - 30
lib/base/get_it.config.dart

@@ -1,30 +0,0 @@
-// GENERATED CODE - DO NOT MODIFY BY HAND
-
-// **************************************************************************
-// InjectableConfigGenerator
-// **************************************************************************
-
-// ignore_for_file: type=lint
-// coverage:ignore-file
-
-// ignore_for_file: no_leading_underscores_for_library_prefixes
-import 'package:get_it/get_it.dart' as _i174;
-import 'package:injectable/injectable.dart' as _i526;
-
-import '../data/repositories/account_repository.dart' as _i20;
-
-extension GetItInjectableX on _i174.GetIt {
-// initializes the registration of main-scope dependencies inside of GetIt
-  _i174.GetIt init({
-    String? environment,
-    _i526.EnvironmentFilter? environmentFilter,
-  }) {
-    final gh = _i526.GetItHelper(
-      this,
-      environment,
-      environmentFilter,
-    );
-    gh.lazySingleton<_i20.AccountRepository>(() => _i20.AccountRepository());
-    return this;
-  }
-}

+ 16 - 0
lib/data/api/atmob_api.dart

@@ -0,0 +1,16 @@
+import 'package:dio/dio.dart';
+import 'package:location/base/base_response.dart';
+import 'package:location/data/api/request/send_code_request.dart';
+import 'package:retrofit/error_logger.dart';
+import 'package:retrofit/http.dart';
+
+part 'atmob_api.g.dart';
+
+@RestApi()
+abstract class AtmobApi {
+  factory AtmobApi(Dio dio, {String baseUrl, ParseErrorLogger? errorLogger}) =
+      _AtmobApi;
+
+  @POST("/s/v1/user/code")
+  Future<BaseResponse> loginSendCode(@Body() SendCodeRequest request);
+}

+ 90 - 0
lib/data/api/atmob_api.g.dart

@@ -0,0 +1,90 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'atmob_api.dart';
+
+// **************************************************************************
+// RetrofitGenerator
+// **************************************************************************
+
+// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers,unused_element,unnecessary_string_interpolations
+
+class _AtmobApi implements AtmobApi {
+  _AtmobApi(
+    this._dio, {
+    this.baseUrl,
+    this.errorLogger,
+  });
+
+  final Dio _dio;
+
+  String? baseUrl;
+
+  final ParseErrorLogger? errorLogger;
+
+  @override
+  Future<BaseResponse<dynamic>> loginSendCode(SendCodeRequest request) async {
+    final _extra = <String, dynamic>{};
+    final queryParameters = <String, dynamic>{};
+    final _headers = <String, dynamic>{};
+    final _data = <String, dynamic>{};
+    _data.addAll(request.toJson());
+    final _options = _setStreamType<BaseResponse<dynamic>>(Options(
+      method: 'POST',
+      headers: _headers,
+      extra: _extra,
+    )
+        .compose(
+          _dio.options,
+          '/s/v1/user/code',
+          queryParameters: queryParameters,
+          data: _data,
+        )
+        .copyWith(
+            baseUrl: _combineBaseUrls(
+          _dio.options.baseUrl,
+          baseUrl,
+        )));
+    final _result = await _dio.fetch<Map<String, dynamic>>(_options);
+    late BaseResponse<dynamic> _value;
+    try {
+      _value = BaseResponse<dynamic>.fromJson(
+        _result.data!,
+        (json) => json as dynamic,
+      );
+    } on Object catch (e, s) {
+      errorLogger?.logError(e, s, _options);
+      rethrow;
+    }
+    return _value;
+  }
+
+  RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
+    if (T != dynamic &&
+        !(requestOptions.responseType == ResponseType.bytes ||
+            requestOptions.responseType == ResponseType.stream)) {
+      if (T == String) {
+        requestOptions.responseType = ResponseType.plain;
+      } else {
+        requestOptions.responseType = ResponseType.json;
+      }
+    }
+    return requestOptions;
+  }
+
+  String _combineBaseUrls(
+    String dioBaseUrl,
+    String? baseUrl,
+  ) {
+    if (baseUrl == null || baseUrl.trim().isEmpty) {
+      return dioBaseUrl;
+    }
+
+    final url = Uri.parse(baseUrl);
+
+    if (url.isAbsolute) {
+      return url.toString();
+    }
+
+    return Uri.parse(dioBaseUrl).resolveUri(url).toString();
+  }
+}

+ 35 - 0
lib/data/api/interceptor/stream_dio_log_interceptor.dart

@@ -0,0 +1,35 @@
+import 'package:dio/dio.dart';
+import 'package:flutter/foundation.dart';
+
+class StreamDioLogInterceptor extends Interceptor {
+  @override
+  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
+    if (kDebugMode) {
+      debugPrint('Stream Request: method[${options.method}],'
+          ' url[${options.uri}],'
+          ' headers[${options.headers}]');
+    }
+    handler.next(options);
+  }
+
+  @override
+  void onError(DioException err, ErrorInterceptorHandler handler) {
+    if (kDebugMode) {
+      debugPrint('Stream Error: type[${err.type}],'
+          ' message[${err.message}],'
+          ' error[${err.error}],'
+          ' stackTrace[${err.stackTrace}]');
+    }
+    handler.next(err);
+  }
+
+  @override
+  void onResponse(Response response, ResponseInterceptorHandler handler) {
+    if (kDebugMode) {
+      debugPrint('Stream Response: header[${response.headers}],'
+          ' statusCode[${response.statusCode}],'
+          ' statusMessage[${response.statusMessage}]');
+    }
+    handler.next(response);
+  }
+}

+ 12 - 0
lib/data/api/request/send_code_request.dart

@@ -0,0 +1,12 @@
+import 'package:json_annotation/json_annotation.dart';
+import 'package:location/base/base_request.dart';
+
+part 'send_code_request.g.dart';
+
+@JsonSerializable()
+class SendCodeRequest extends BaseRequest {
+  @JsonKey(name: "phone")
+  final String phoneNum;
+
+  SendCodeRequest(this.phoneNum);
+}

+ 67 - 0
lib/data/api/request/send_code_request.g.dart

@@ -0,0 +1,67 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'send_code_request.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+SendCodeRequest _$SendCodeRequestFromJson(Map<String, dynamic> json) =>
+    SendCodeRequest(
+      json['phone'] as String,
+    )
+      ..appPlatform = (json['appPlatform'] as num).toInt()
+      ..os = json['os'] as String
+      ..osVersion = json['osVersion'] as String
+      ..packageName = json['packageName'] as String?
+      ..appVersionName = json['appVersionName'] as String?
+      ..appVersionCode = (json['appVersionCode'] as num?)?.toInt()
+      ..channelName = json['channelName'] as String?
+      ..appId = (json['appId'] as num?)?.toInt()
+      ..tgPlatform = (json['tgPlatform'] as num?)?.toInt()
+      ..oaid = json['oaid'] as String?
+      ..aaid = json['aaid'] as String?
+      ..androidId = json['androidId'] as String?
+      ..imei = json['imei'] as String?
+      ..simImei0 = json['simImei0'] as String?
+      ..simImei1 = json['simImei1'] as String?
+      ..mac = json['mac'] as String?
+      ..idfa = json['idfa'] as String?
+      ..idfv = json['idfv'] as String?
+      ..machineId = json['machineId'] as String?
+      ..brand = json['brand'] as String?
+      ..model = json['model'] as String?
+      ..wifiName = json['wifiName'] as String?
+      ..region = json['region'] as String?
+      ..locLng = (json['locLng'] as num?)?.toDouble()
+      ..locLat = (json['locLat'] as num?)?.toDouble();
+
+Map<String, dynamic> _$SendCodeRequestToJson(SendCodeRequest instance) =>
+    <String, dynamic>{
+      'appPlatform': instance.appPlatform,
+      'os': instance.os,
+      'osVersion': instance.osVersion,
+      'packageName': instance.packageName,
+      'appVersionName': instance.appVersionName,
+      'appVersionCode': instance.appVersionCode,
+      'channelName': instance.channelName,
+      'appId': instance.appId,
+      'tgPlatform': instance.tgPlatform,
+      'oaid': instance.oaid,
+      'aaid': instance.aaid,
+      'androidId': instance.androidId,
+      'imei': instance.imei,
+      'simImei0': instance.simImei0,
+      'simImei1': instance.simImei1,
+      'mac': instance.mac,
+      'idfa': instance.idfa,
+      'idfv': instance.idfv,
+      'machineId': instance.machineId,
+      'brand': instance.brand,
+      'model': instance.model,
+      'wifiName': instance.wifiName,
+      'region': instance.region,
+      'locLng': instance.locLng,
+      'locLat': instance.locLat,
+      'phone': instance.phoneNum,
+    };

+ 34 - 0
lib/data/bean/location_info.dart

@@ -0,0 +1,34 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'location_info.g.dart';
+
+@JsonSerializable()
+class LocationInfo {
+  @JsonKey(name: 'userId')
+  final String userId;
+
+  @JsonKey(name: 'lng')
+  final double? longitude;
+
+  @JsonKey(name: 'lat')
+  final double? latitude;
+
+  @JsonKey(name: 'addr')
+  final String? address;
+
+  @JsonKey(name: 'timestamp')
+  final int? lastUpdateTime;
+
+  LocationInfo({
+    required this.userId,
+    this.longitude,
+    this.latitude,
+    this.address,
+    this.lastUpdateTime,
+  });
+
+  factory LocationInfo.fromJson(Map<String, dynamic> json) =>
+      _$LocationInfoFromJson(json);
+
+  Map<String, dynamic> toJson() => _$LocationInfoToJson(this);
+}

+ 51 - 0
lib/data/bean/user_info.dart

@@ -0,0 +1,51 @@
+import 'package:json_annotation/json_annotation.dart';
+
+import 'location_info.dart';
+
+part 'user_info.g.dart';
+
+@JsonSerializable()
+class UserInfo {
+  @JsonKey(name: 'friendId')
+  final String id;
+
+  @JsonKey(name: 'phone')
+  final String phoneNumber;
+
+  @JsonKey(name: 'remark')
+  String? remark;
+
+  @JsonKey(name: 'timestamp')
+  final int? timestamp;
+
+  @JsonKey(name: 'blockedHim')
+  final bool? blockedHim;
+
+  @JsonKey(name: 'blockedMe')
+  final bool? blockedMe;
+
+  @JsonKey(name: 'location')
+  final LocationInfo? lastLocation;
+
+  @JsonKey(name: 'virtual')
+  final bool? virtual;
+
+  final bool? isMine;
+
+  UserInfo({
+    required this.id,
+    required this.phoneNumber,
+    this.remark,
+    this.timestamp,
+    this.blockedHim,
+    this.blockedMe,
+    this.lastLocation,
+    this.virtual,
+    this.isMine,
+  });
+
+  factory UserInfo.fromJson(Map<String, dynamic> json) =>
+      _$UserInfoFromJson(json);
+
+  Map<String, dynamic> toJson() => _$UserInfoToJson(this);
+}

+ 50 - 0
lib/data/consts/constants.dart

@@ -0,0 +1,50 @@
+import '../../utils/mmkv_util.dart';
+
+class Constants {
+  Constants._();
+
+  static const String env = envProd;
+
+  static const String envDev = 'dev';
+
+  static const String envTest = 'test';
+
+  static const String envProd = 'prod';
+
+  static const String _devBaseUrl = "http://192.168.10.230:8880";
+
+  static const String _testBaseUrl = "http://42.193.245.11";
+
+  static const String _prodBaseUrl = "https://project-api.atmob.com";
+
+  static const String privacyPolicy =
+      "https://doc.v8dashen.com/doc/298eb75d38dc2c4a";
+
+  static const String userAgreement =
+      "https://doc.v8dashen.com/doc/417838a4f155ec74";
+
+  static String baseUrl = getBaseUrl();
+
+  static const String isPolicyGranted = 'isPolicyGranted';
+
+  static bool isProdEnv() {
+    return Constants.env == Constants.envProd;
+  }
+}
+
+String getBaseUrl() {
+  switch (Constants.env) {
+    case Constants.envDev:
+      return Constants._devBaseUrl;
+    case Constants.envTest:
+      return Constants._testBaseUrl;
+    case Constants.envProd:
+      return Constants._prodBaseUrl;
+    default:
+      return Constants._devBaseUrl;
+  }
+}
+
+bool isAgreePrivacyPolicy() {
+  return KVUtil.getBool(Constants.isPolicyGranted, false);
+}

+ 14 - 1
lib/data/repositories/account_repository.dart

@@ -1,4 +1,17 @@
 import 'package:injectable/injectable.dart';
+import 'package:location/data/api/atmob_api.dart';
+import 'package:location/data/api/request/send_code_request.dart';
+import 'package:location/utils/http_handler.dart';
 
 @lazySingleton
-class AccountRepository {}
+class AccountRepository {
+  final AtmobApi atmobApi;
+
+  AccountRepository(this.atmobApi);
+
+  Future<void> loginSendCode(String phoneNum) {
+    return atmobApi
+        .loginSendCode(SendCodeRequest(phoneNum))
+        .then(HttpHandler.handle(true));
+  }
+}

+ 168 - 0
lib/device/atmob_platform_info.dart

@@ -0,0 +1,168 @@
+class AtmobPlatformInfo {
+  AtmobPlatformInfo();
+
+  /// 设备信息
+  /// Android特有
+  String? _oaid;
+  String? _aaid;
+  String? _androidId;
+  String? _imei;
+  String? _simImei0;
+  String? _simImei1;
+  String? _mac;
+
+  //渠道信息
+  String? _channelName;
+  int? _appId;
+  int? _tgPlatform;
+
+  /// iOS特有
+  String? _idfa;
+  String? _idfv;
+
+  /// 公共设备信息
+  String? _machineId; //给web使用
+  String? _brand;
+  String? _model;
+  String? _wifiName;
+
+  /// 地理位置信息
+  String? _region;
+  double? _locLng;
+  double? _locLat;
+
+  AtmobPlatformInfo setChannelName(String? channelName) {
+    _channelName = channelName;
+    return this;
+  }
+
+  AtmobPlatformInfo setTgPlatform(int? tgPlatform) {
+    _tgPlatform = tgPlatform;
+    return this;
+  }
+
+  AtmobPlatformInfo setAppId(int? appId) {
+    _appId = appId;
+    return this;
+  }
+
+  AtmobPlatformInfo setOaid(String? oaid) {
+    _oaid = oaid;
+    return this;
+  }
+
+  AtmobPlatformInfo setAaid(String? aaid) {
+    _aaid = aaid;
+    return this;
+  }
+
+  AtmobPlatformInfo setAndroidId(String? androidId) {
+    _androidId = androidId;
+    return this;
+  }
+
+  AtmobPlatformInfo setImei(String? imei) {
+    _imei = imei;
+    return this;
+  }
+
+  AtmobPlatformInfo setSimImei0(String? simImei0) {
+    _simImei0 = simImei0;
+    return this;
+  }
+
+  AtmobPlatformInfo setSimImei1(String? simImei1) {
+    _simImei1 = simImei1;
+    return this;
+  }
+
+  AtmobPlatformInfo setMac(String? mac) {
+    _mac = mac;
+    return this;
+  }
+
+  AtmobPlatformInfo setIdfa(String? idfa) {
+    _idfa = idfa;
+    return this;
+  }
+
+  AtmobPlatformInfo setIdfv(String? idfv) {
+    _idfv = idfv;
+    return this;
+  }
+
+  AtmobPlatformInfo setMachineId(String? machineId) {
+    _machineId = machineId;
+    return this;
+  }
+
+  AtmobPlatformInfo setBrand(String? brand) {
+    _brand = brand;
+    return this;
+  }
+
+  AtmobPlatformInfo setModel(String? model) {
+    _model = model;
+    return this;
+  }
+
+  AtmobPlatformInfo setWifiName(String? wifiName) {
+    _wifiName = wifiName;
+    return this;
+  }
+
+  AtmobPlatformInfo setRegion(String? region) {
+    _region = region;
+    return this;
+  }
+
+  AtmobPlatformInfo setLocLng(double? locLng) {
+    _locLng = locLng;
+    return this;
+  }
+
+  AtmobPlatformInfo setLocLat(double? locLat) {
+    _locLat = locLat;
+    return this;
+  }
+
+  double? get locLat => _locLat;
+
+  double? get locLng => _locLng;
+
+  String? get region => _region;
+
+  String? get wifiName => _wifiName;
+
+  String? get model => _model;
+
+  String? get brand => _brand;
+
+  String? get machineId => _machineId;
+
+  String? get idfv => _idfv;
+
+  String? get idfa => _idfa;
+
+  String? get mac => _mac;
+
+  String? get simImei1 => _simImei1;
+
+  String? get simImei0 => _simImei0;
+
+  String? get imei => _imei;
+
+  String? get androidId => _androidId;
+
+  String? get aaid => _aaid;
+
+  String? get oaid => _oaid;
+
+  String? get channelName => _channelName;
+
+  int? get tgPlatform => _tgPlatform;
+
+  int? get appId => _appId;
+}
+
+final AtmobPlatformInfo atmobPlatformInfo = AtmobPlatformInfo();

+ 13 - 0
lib/device/device_info_util.dart

@@ -0,0 +1,13 @@
+import 'package:location/device/platform_ios_info.dart';
+import 'platform_android_info.dart';
+
+class DeviceInfoUtil {
+  DeviceInfoUtil._();
+
+  init() async {
+    await PlatformAndroidInfo.init();
+    await PlatformIosInfo.init();
+  }
+}
+
+final deviceInfoUtil = DeviceInfoUtil._();

+ 19 - 0
lib/device/platform_android_info.dart

@@ -0,0 +1,19 @@
+import 'dart:io';
+
+import 'package:device_info_plus/device_info_plus.dart';
+import 'package:android_id/android_id.dart';
+import 'atmob_platform_info.dart';
+
+class PlatformAndroidInfo {
+  static Future<void> init() async {
+    if (Platform.isAndroid) {
+      DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
+      AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
+      String? deviceId = await const AndroidId().getId();
+      atmobPlatformInfo
+          .setAndroidId(deviceId)
+          .setBrand(androidInfo.brand)
+          .setModel(androidInfo.model);
+    }
+  }
+}

+ 32 - 0
lib/device/platform_ios_info.dart

@@ -0,0 +1,32 @@
+import 'dart:io';
+
+import 'package:app_tracking_transparency/app_tracking_transparency.dart';
+import 'package:device_info_plus/device_info_plus.dart';
+
+import 'atmob_platform_info.dart';
+
+class PlatformIosInfo {
+  static Future<void> init() async {
+    if (Platform.isIOS) {
+      DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
+      IosDeviceInfo iosInfo = await deviceInfoPlugin.iosInfo;
+      atmobPlatformInfo
+          .setModel(iosInfo.model)
+          .setIdfv(iosInfo.identifierForVendor);
+
+      final TrackingStatus status =
+          await AppTrackingTransparency.trackingAuthorizationStatus;
+      if (status == TrackingStatus.notDetermined) {
+        final TrackingStatus newStatus =
+            await AppTrackingTransparency.requestTrackingAuthorization();
+        if (newStatus == TrackingStatus.authorized) {
+          atmobPlatformInfo.setIdfa(
+              await AppTrackingTransparency.getAdvertisingIdentifier());
+        }
+      } else if (status == TrackingStatus.authorized) {
+        atmobPlatformInfo
+            .setIdfa(await AppTrackingTransparency.getAdvertisingIdentifier());
+      }
+    }
+  }
+}

+ 47 - 0
lib/di/get_it.config.dart

@@ -0,0 +1,47 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+// **************************************************************************
+// InjectableConfigGenerator
+// **************************************************************************
+
+// ignore_for_file: type=lint
+// coverage:ignore-file
+
+// ignore_for_file: no_leading_underscores_for_library_prefixes
+import 'package:dio/dio.dart' as _i361;
+import 'package:get_it/get_it.dart' as _i174;
+import 'package:injectable/injectable.dart' as _i526;
+
+import '../data/api/atmob_api.dart' as _i243;
+import '../data/repositories/account_repository.dart' as _i20;
+import '../module/add_friend/add_friend_dialog_controller.dart' as _i897;
+import '../module/main/main_controller.dart' as _i731;
+import '../module/splash/splash_controller.dart' as _i973;
+import 'network_module.dart' as _i567;
+
+extension GetItInjectableX on _i174.GetIt {
+// initializes the registration of main-scope dependencies inside of GetIt
+  _i174.GetIt init({
+    String? environment,
+    _i526.EnvironmentFilter? environmentFilter,
+  }) {
+    final gh = _i526.GetItHelper(
+      this,
+      environment,
+      environmentFilter,
+    );
+    final networkModule = _$NetworkModule();
+    gh.factory<_i731.MainController>(() => _i731.MainController());
+    gh.factory<_i973.SplashController>(() => _i973.SplashController());
+    gh.singleton<_i361.Dio>(() => networkModule.createDefaultDio());
+    gh.singleton<_i243.AtmobApi>(
+        () => networkModule.provideAtmobApi(gh<_i361.Dio>()));
+    gh.lazySingleton<_i20.AccountRepository>(
+        () => _i20.AccountRepository(gh<_i243.AtmobApi>()));
+    gh.factory<_i897.AddFriendDialogController>(
+        () => _i897.AddFriendDialogController(gh<_i20.AccountRepository>()));
+    return this;
+  }
+}
+
+class _$NetworkModule extends _i567.NetworkModule {}

+ 4 - 4
lib/base/get_it.dart

@@ -1,12 +1,12 @@
 import 'package:injectable/injectable.dart';
 import 'package:get_it/get_it.dart';
-import 'package:location/base/get_it.config.dart';
+import 'package:location/di/get_it.config.dart';
 
 final getIt = GetIt.instance;
 
 @InjectableInit(
-  initializerName: 'init', // default
-  preferRelativeImports: true, // default
-  asExtension: true, // default
+  initializerName: 'init',
+  preferRelativeImports: true,
+  asExtension: true,
 )
 void configureDependencies() => getIt.init();

+ 10 - 20
lib/di/network_module.dart

@@ -1,10 +1,14 @@
 import 'package:dio/dio.dart';
+import 'package:injectable/injectable.dart';
+import 'package:location/data/api/atmob_api.dart';
+import 'package:location/data/consts/constants.dart';
 import 'package:pretty_dio_logger/pretty_dio_logger.dart';
-
 import '../data/consts/build_config.dart';
 
-class _NetworkModule {
-  static Dio _createDefaultDio() {
+@module
+abstract class NetworkModule {
+  @singleton
+  Dio createDefaultDio() {
     Dio dio = Dio(BaseOptions());
     dio.interceptors.add(PrettyDioLogger(
       requestHeader: true,
@@ -18,22 +22,8 @@ class _NetworkModule {
     return dio;
   }
 
-  static Dio _createFileDio() {
-    Dio dio = Dio(BaseOptions(
-      sendTimeout: const Duration(seconds: 15),
-      receiveTimeout: const Duration(seconds: 15),
-    ));
-    dio.interceptors.add(PrettyDioLogger(
-      requestHeader: true,
-      requestBody: true,
-      responseBody: true,
-      responseHeader: true,
-      enabled: BuildConfig.isDebug,
-    ));
-    return dio;
+  @singleton
+  AtmobApi provideAtmobApi(Dio dio) {
+    return AtmobApi(dio, baseUrl: Constants.baseUrl);
   }
 }
-
-final defaultDio = _NetworkModule._createDefaultDio();
-
-final fileDio = _NetworkModule._createFileDio();

+ 42 - 1
lib/main.dart

@@ -7,18 +7,59 @@ import 'package:location/resource/colors.gen.dart';
 import 'package:location/resource/string.gen.dart';
 import 'package:location/resource/string_source.dart';
 import 'package:location/router/app_pages.dart';
+import 'package:location/utils/app_info_util.dart';
+import 'package:location/utils/mmkv_util.dart';
+import 'package:location/utils/toast_util.dart';
 import 'package:pull_to_refresh/pull_to_refresh.dart';
 
-import 'base/get_it.dart';
+import 'di/get_it.dart';
+import 'data/consts/build_config.dart';
+import 'data/consts/constants.dart';
+import 'device/device_info_util.dart';
 
 void main() async {
   WidgetsFlutterBinding.ensureInitialized();
 
   configureDependencies();
 
+  //mmkv存储
+  await KVUtil.init();
+
+  //非隐私相关
+  initCommon();
+
+  //檢查地址
+  checkEnv();
+
   runApp(const MyApp());
 }
 
+void initCommon() {
+  //全局配置smartDialog
+  smartConfig();
+}
+
+void smartConfig() {
+  SmartDialog.config.custom =
+      SmartConfigCustom(animationType: SmartAnimationType.fade);
+}
+
+Future<void> initAfterGrant() async {
+  // if (!isAgreePrivacyPolicy()) {
+  //   return;
+  // }
+  //获取包信息
+  await appInfoUtil.init();
+  //获取设备信息
+  await deviceInfoUtil.init();
+}
+
+void checkEnv() {
+  if (!Constants.isProdEnv() && !BuildConfig.isDebug) {
+    ToastUtil.show('不是正式环境!!!', addPostFrame: true);
+  }
+}
+
 class MyApp extends StatelessWidget {
   const MyApp({super.key});
 

+ 25 - 0
lib/module/add_friend/add_friend_dialog_controller.dart

@@ -0,0 +1,25 @@
+import 'package:get/get.dart';
+import 'package:injectable/injectable.dart';
+import 'package:location/data/repositories/account_repository.dart';
+import '../../../base/base_controller.dart';
+import '../../utils/atmob_log.dart';
+
+@injectable
+class AddFriendDialogController extends BaseController {
+  final AccountRepository accountRepository;
+
+  final title = ''.obs;
+
+  AddFriendDialogController(this.accountRepository) {
+    AtmobLog.d("zk", 'AddFriendDialogController .. constructor');
+  }
+
+  @override
+  void onInit() {
+    accountRepository.loginSendCode('123').then((data) {
+      AtmobLog.d("zk", '1');
+    }).catchError((error) {
+      AtmobLog.d("zk", '$error');
+    });
+  }
+}

+ 5 - 4
lib/module/friend/add_friend/add_friend_view.dart

@@ -60,10 +60,11 @@ class AddFriendView extends BaseView<AddFriendDialogController> {
                 SizedBox(height: 16.h),
                 _buildShareWx(),
                 SizedBox(height: 20.h),
-                Center(
-                    child: Text(StringName.friendAddRule,
-                        style: TextStyle(
-                            fontSize: 12.sp, color: '#A7A7A7'.color))),
+                Center(child: Obx(() {
+                  return Text(controller.title.value,
+                      style:
+                          TextStyle(fontSize: 12.sp, color: '#A7A7A7'.color));
+                })),
                 SizedBox(height: 30.h),
               ],
             )

+ 0 - 3
lib/module/friend/add_friend/add_friend_dialog_controller.dart

@@ -1,3 +0,0 @@
-import '../../../base/base_controller.dart';
-
-class AddFriendDialogController extends BaseController {}

+ 9 - 1
lib/module/main/main_controller.dart

@@ -1,3 +1,11 @@
+import 'package:injectable/injectable.dart';
 import 'package:location/base/base_controller.dart';
 
-class MainController extends BaseController {}
+import '../add_friend/add_friend_view.dart';
+
+@injectable
+class MainController extends BaseController {
+  void onAddFriendClick() {
+    AddFriendView.show();
+  }
+}

+ 9 - 4
lib/module/main/main_page.dart

@@ -105,10 +105,15 @@ class MainPage extends BasePage<MainController> {
             child: Row(
               children: [
                 Expanded(child: Text('好友列表')),
-                Container(
-                    margin: EdgeInsets.only(right: 16.w, left: 8.w),
-                    child: Assets.images.iconMainAddFriend
-                        .image(width: 60.w, height: 60.w))
+                GestureDetector(
+                  onTap: () {
+                    controller.onAddFriendClick();
+                  },
+                  child: Container(
+                      margin: EdgeInsets.only(right: 16.w, left: 8.w),
+                      child: Assets.images.iconMainAddFriend
+                          .image(width: 60.w, height: 60.w)),
+                )
               ],
             ),
           ),

+ 2 - 0
lib/module/splash/splash_controller.dart

@@ -1,5 +1,7 @@
+import 'package:injectable/injectable.dart';
 import 'package:location/base/base_controller.dart';
 
+@injectable
 class SplashController extends BaseController {
   @override
   void onReady() {}

+ 6 - 5
lib/router/app_pages.dart

@@ -1,6 +1,7 @@
 import 'package:get/get.dart';
-import 'package:location/module/friend/add_friend/add_friend_dialog_controller.dart';
+import 'package:location/di/get_it.dart';
 import 'package:location/module/main/main_page.dart';
+import '../module/add_friend/add_friend_dialog_controller.dart';
 import '../module/main/main_controller.dart';
 import '../module/splash/splash_controller.dart';
 import '../module/splash/splash_page.dart';
@@ -18,9 +19,9 @@ abstract class RoutePath {
 class AppBinding extends Bindings {
   @override
   void dependencies() {
-    lazyPut(() => SplashController());
-    lazyPut(() => MainController());
-    lazyPut(() => AddFriendDialogController());
+    lazyPut(() => getIt.get<SplashController>());
+    lazyPut(() => getIt.get<MainController>());
+    lazyPut(() => getIt.get<AddFriendDialogController>());
   }
 
   void lazyPut<S>(InstanceBuilderCallback<S> builder) {
@@ -29,6 +30,6 @@ class AppBinding extends Bindings {
 }
 
 final generalPages = [
-  GetPage(name: RoutePath.splash, page: () => const SplashPage()),
+  GetPage(name: RoutePath.splash, page: () => SplashPage()),
   GetPage(name: RoutePath.mainTab, page: () => MainPage()),
 ];

+ 23 - 0
lib/utils/app_info_util.dart

@@ -0,0 +1,23 @@
+import 'dart:io';
+
+import 'package:package_info_plus/package_info_plus.dart';
+
+class AppInfoUtil {
+  PackageInfo? _packageInfo;
+
+  AppInfoUtil._();
+
+  init() async {
+    _packageInfo = await PackageInfo.fromPlatform();
+  }
+
+  String? get appName => _packageInfo?.appName;
+
+  String? get packageName => "com.manbu.shouji";
+
+  String? get appVersionName => '3.2.1';
+
+  int? get appVersionCode => 321;
+}
+
+final appInfoUtil = AppInfoUtil._();

+ 29 - 0
lib/utils/atmob_log.dart

@@ -0,0 +1,29 @@
+import 'package:atmob_logging/atmob_logging.dart';
+
+class AtmobLog {
+  AtmobLog._();
+
+  static void w(String tag, String message) {
+    ALog.w(tag, message);
+  }
+
+  static void e(String tag, String message) {
+    ALog.e(tag, message);
+  }
+
+  static void i(String tag, String message) {
+    ALog.i(tag, message);
+  }
+
+  static void d(String tag, String message) {
+    ALog.d(tag, message);
+  }
+
+  static void v(String tag, String message) {
+    ALog.v(tag, message);
+  }
+
+  static void setLogLevel(LogLevel level) {
+    ALog.setLogLevel(level);
+  }
+}

+ 34 - 0
lib/utils/http_handler.dart

@@ -0,0 +1,34 @@
+import 'dart:async';
+
+import '../base/base_response.dart';
+
+class HttpHandler {
+  HttpHandler._();
+
+  static FutureOr<T> Function(BaseResponse<T> value) handle<T>(
+      bool allowEmptyData) {
+    return (BaseResponse<T> response) {
+      if (response.code == 0) {
+        if (response.data != null || allowEmptyData) {
+          return response.data == null ? Future.value() : response.data!;
+        } else {
+          throw Exception('data is null');
+        }
+      } else {
+        throw ServerErrorException(response.code, response.message);
+      }
+    };
+  }
+}
+
+class ServerErrorException implements Exception {
+  final int? code;
+  final String? message;
+
+  ServerErrorException(this.code, this.message);
+
+  @override
+  String toString() {
+    return 'ServerErrorException: code: $code, message: $message';
+  }
+}

+ 52 - 0
lib/utils/mmkv_util.dart

@@ -0,0 +1,52 @@
+import 'package:mmkv/mmkv.dart';
+
+class KVUtil {
+  KVUtil._();
+
+  static MMKV? _mmkv;
+
+  static init() async {
+    if (_mmkv != null) {
+      return;
+    }
+    await MMKV.initialize();
+    _mmkv = MMKV.defaultMMKV();
+  }
+
+  static void putString(String key, String? value) {
+    _getMMKV().encodeString(key, value);
+  }
+
+  static String? getString(String key, String? defaultValue) {
+    return _getMMKV().decodeString(key) ?? defaultValue;
+  }
+
+  static void putInt(String key, int value) {
+    _getMMKV().encodeInt(key, value);
+  }
+
+  static int getInt(String key, int defaultValue) {
+    return _getMMKV().decodeInt(key, defaultValue: defaultValue);
+  }
+
+  static void putBool(String key, bool value) {
+    _getMMKV().encodeBool(key, value);
+  }
+
+  static bool getBool(String key, bool defaultValue) {
+    return _getMMKV().decodeBool(key, defaultValue: defaultValue);
+  }
+
+  static void putDouble(String key, double value) {
+    _getMMKV().encodeDouble(key, value);
+  }
+
+  static double getDouble(String key, double defaultValue) {
+    return _getMMKV().decodeDouble(key, defaultValue: defaultValue);
+  }
+
+  static MMKV _getMMKV() {
+    _mmkv ??= MMKV.defaultMMKV();
+    return _mmkv!;
+  }
+}

+ 23 - 0
lib/utils/toast_util.dart

@@ -0,0 +1,23 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
+
+class ToastUtil {
+  ToastUtil._();
+
+  static void show(String? msg,
+      {Duration? displayTime,
+      SmartToastType? displayType = SmartToastType.normal,
+      bool? addPostFrame}) {
+    if (msg != null) {
+      if (addPostFrame == true) {
+        WidgetsBinding.instance.addPostFrameCallback((_) {
+          SmartDialog.showToast(msg,
+              displayType: displayType, displayTime: displayTime);
+        });
+      } else {
+        SmartDialog.showToast(msg,
+            displayType: displayType, displayTime: displayTime);
+      }
+    }
+  }
+}

+ 24 - 0
pubspec.lock

@@ -30,6 +30,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.4.0"
+  app_tracking_transparency:
+    dependency: "direct main"
+    description:
+      name: app_tracking_transparency
+      sha256: "7b011da3165ebb5a2f93d19da22e43a94b45bb6471c825b7d163b30eff937d30"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.5"
   archive:
     dependency: transitive
     description:
@@ -786,6 +794,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.4.0"
+  protobuf:
+    dependency: transitive
+    description:
+      name: protobuf
+      sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.0"
   pub_semver:
     dependency: transitive
     description:
@@ -826,6 +842,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "4.4.1"
+  retrofit_generator:
+    dependency: "direct dev"
+    description:
+      name: retrofit_generator
+      sha256: f76fdb2b66854690d5a332e7364d7561fc9dc2b3c924d7956ab8070495e21f6a
+      url: "https://pub.dev"
+    source: hosted
+    version: "9.1.5"
   shelf:
     dependency: transitive
     description:

+ 5 - 1
pubspec.yaml

@@ -47,6 +47,9 @@ dependencies:
   # 包信息
   package_info_plus: 8.1.1
 
+  # 隐私追踪
+  app_tracking_transparency: ^2.0.5
+
   # 屏幕适配
   flutter_screenutil: 5.9.3
 
@@ -60,7 +63,7 @@ dependencies:
   permission_handler: 11.3.1
 
   #上、下拉刷新
-  pull_to_refresh: ^2.0.0
+  pull_to_refresh: 2.0.0
 
   #本地化
   flutter_localizations:
@@ -87,6 +90,7 @@ dev_dependencies:
   flutter_test:
     sdk: flutter
 
+  retrofit_generator: '>=8.0.0 <10.0.0'
 
   build_runner: 2.4.13