WT 1.1.7+2 SearchBar, Timer for ExerciseControl
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class AppLanguage with Logging {
|
||||
static final AppLanguage _singleton = AppLanguage._internal();
|
||||
|
||||
Locale _appLocale = Locale('en');
|
||||
|
||||
factory AppLanguage() {
|
||||
return _singleton;
|
||||
}
|
||||
|
||||
AppLanguage._internal();
|
||||
|
||||
static Future<AppLanguage> getInstance() async {
|
||||
return _singleton;
|
||||
}
|
||||
|
||||
Locale get appLocal => _appLocale ?? Locale("en");
|
||||
|
||||
Future<void> fetchLocale() async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
String langCode = prefs.getString('language_code');
|
||||
log(" ---- lang code $langCode");
|
||||
if (langCode == null) {
|
||||
_appLocale = Locale('en');
|
||||
} else {
|
||||
_appLocale = Locale(langCode);
|
||||
}
|
||||
log(" ---- Fetched lang: " + _appLocale.toString());
|
||||
}
|
||||
|
||||
getLocale(SharedPreferences prefs) {
|
||||
String langCode = prefs.getString('language_code');
|
||||
if (langCode == null) {
|
||||
final String localName = Platform.localeName;
|
||||
if (localName.endsWith("HU")) {
|
||||
_appLocale = Locale('hu');
|
||||
langCode = "hu";
|
||||
} else {
|
||||
_appLocale = Locale('en');
|
||||
langCode = "en";
|
||||
}
|
||||
}
|
||||
_appLocale = Locale(langCode);
|
||||
log(" ---- Get lang: " + _appLocale.toString() + " lang code $langCode");
|
||||
}
|
||||
|
||||
void changeLanguage(Locale type) async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
if (_appLocale == type) {
|
||||
return;
|
||||
}
|
||||
if (type == Locale("hu")) {
|
||||
_appLocale = Locale("hu");
|
||||
await prefs.setString('language_code', 'hu');
|
||||
await prefs.setString('countryCode', 'HU');
|
||||
} else {
|
||||
_appLocale = Locale("en");
|
||||
await prefs.setString('language_code', 'en');
|
||||
await prefs.setString('countryCode', 'US');
|
||||
}
|
||||
log(" ---- Stored lang: " + _appLocale.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class AppLocalizations with Logging {
|
||||
Locale locale;
|
||||
bool isTest;
|
||||
|
||||
AppLocalizations(this.locale, {this.isTest = false});
|
||||
|
||||
// Helper method to keep the code in the widgets concise
|
||||
// Localizations are accessed using an InheritedWidget "of" syntax
|
||||
static AppLocalizations of(BuildContext context) {
|
||||
return Localizations.of<AppLocalizations>(context, AppLocalizations);
|
||||
}
|
||||
|
||||
// Static member to have a simple access to the delegate from the MaterialApp
|
||||
static const LocalizationsDelegate<AppLocalizations> delegate = AppLocalizationsDelegate();
|
||||
|
||||
Map<String, String> _localizedStrings;
|
||||
|
||||
setLocale(Locale locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
Future<bool> load() async {
|
||||
// Load the language JSON file from the "lang" folder
|
||||
log(" -- load language pieces " + locale.languageCode);
|
||||
String jsonString = await rootBundle.loadString('i18n/${locale.languageCode}.json');
|
||||
Map<String, dynamic> jsonMap = json.decode(jsonString);
|
||||
|
||||
_localizedStrings = jsonMap.map((key, value) {
|
||||
return MapEntry(key, value.toString());
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Future<AppLocalizations> loadTest(Locale locale) async {
|
||||
return AppLocalizations(locale);
|
||||
}
|
||||
|
||||
// This method will be called from every widget which needs a localized text
|
||||
String translate(String key) {
|
||||
if (isTest) return key;
|
||||
String translated = _localizedStrings[key];
|
||||
return translated != null ? translated : key;
|
||||
}
|
||||
}
|
||||
|
||||
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
|
||||
final bool isTest;
|
||||
// This delegate instance will never change (it doesn't even have fields!)
|
||||
// It can provide a constant constructor.
|
||||
const AppLocalizationsDelegate({this.isTest = false});
|
||||
|
||||
@override
|
||||
bool isSupported(Locale locale) {
|
||||
// Include all of your supported language codes here
|
||||
return ['en', 'hu'].contains(locale.languageCode);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AppLocalizations> load(Locale locale) async {
|
||||
// AppLocalizations class is where the JSON loading actually runs
|
||||
AppLocalizations localizations = new AppLocalizations(locale, isTest: this.isTest);
|
||||
if (isTest) {
|
||||
await localizations.loadTest(locale);
|
||||
} else {
|
||||
await localizations.load();
|
||||
}
|
||||
return localizations;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReload(AppLocalizationsDelegate old) => false;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||
import 'package:aitrainer_app/repository/user_repository.dart';
|
||||
|
||||
+9
-1
@@ -36,7 +36,7 @@ enum TrackingEvent {
|
||||
my_special_plan,
|
||||
my_suggested_plan,
|
||||
prediction,
|
||||
|
||||
search,
|
||||
exercise_device,
|
||||
customer_change,
|
||||
settings_lang,
|
||||
@@ -62,3 +62,11 @@ extension PropertyExt on PropertyEnum {
|
||||
bool equalsTo(PropertyEnum event) => this.toString() == event.toString();
|
||||
bool equalsStringTo(String event) => this.toString() == event;
|
||||
}
|
||||
|
||||
enum SizesEnum { Weight, Height, Shoulder, Neck, Biceps, Chest, Belly, Hip, ThighTop, ThighMiddle, Knee, Calf, Ankle, Underarm, Lowerarm }
|
||||
|
||||
extension SizesExt on SizesEnum {
|
||||
String toStr() => this.toString().split(".").last;
|
||||
bool equalsTo(SizesEnum event) => this.toString() == event.toString();
|
||||
bool equalsStringTo(String event) => this.toString() == event;
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
/*
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/product.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:in_app_purchase/in_app_purchase.dart';
|
||||
|
||||
class PlatformPurchaseApi with Logging {
|
||||
static final PlatformPurchaseApi _singleton = PlatformPurchaseApi._internal();
|
||||
|
||||
bool _kAutoConsume = true;
|
||||
final String _kConsumableId = 'consumable';
|
||||
final InAppPurchaseConnection _connection = InAppPurchaseConnection.instance;
|
||||
bool _isAvailable = false;
|
||||
List<ProductDetails> _products = [];
|
||||
List<PurchaseDetails> _purchases = [];
|
||||
List<String> _notFoundIds = [];
|
||||
List<String> _consumables = [];
|
||||
bool _purchasePending = false;
|
||||
String _queryProductError;
|
||||
|
||||
StreamSubscription<List<PurchaseDetails>> _subscription;
|
||||
|
||||
final List<String> _productList = List();
|
||||
|
||||
List getProductList() => _productList;
|
||||
|
||||
factory PlatformPurchaseApi() {
|
||||
return _singleton;
|
||||
}
|
||||
|
||||
PlatformPurchaseApi._internal();
|
||||
|
||||
Future<void> close() async {
|
||||
_subscription.cancel();
|
||||
}
|
||||
|
||||
Future<void> initStoreInfo() async {
|
||||
final bool isAvailable = await _connection.isAvailable();
|
||||
if (!isAvailable) {
|
||||
_isAvailable = isAvailable;
|
||||
_products = [];
|
||||
_purchases = [];
|
||||
_notFoundIds = [];
|
||||
_consumables = [];
|
||||
_purchasePending = false;
|
||||
log("Payment processor not available");
|
||||
return;
|
||||
}
|
||||
|
||||
getSubscriptions();
|
||||
ProductDetailsResponse productDetailResponse = await _connection.queryProductDetails(_productList.toSet());
|
||||
log("ProductDetailsResponse " + productDetailResponse.toString());
|
||||
if (productDetailResponse.error != null) {
|
||||
_queryProductError = productDetailResponse.error.message;
|
||||
_isAvailable = isAvailable;
|
||||
_products = productDetailResponse.productDetails;
|
||||
_purchases = [];
|
||||
_notFoundIds = productDetailResponse.notFoundIDs;
|
||||
_consumables = [];
|
||||
_purchasePending = false;
|
||||
log("Payment processor not available");
|
||||
return;
|
||||
}
|
||||
|
||||
if (productDetailResponse.productDetails.isEmpty) {
|
||||
_queryProductError = null;
|
||||
_isAvailable = isAvailable;
|
||||
_products = productDetailResponse.productDetails;
|
||||
_purchases = [];
|
||||
_notFoundIds = productDetailResponse.notFoundIDs;
|
||||
_consumables = [];
|
||||
_purchasePending = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
_products = productDetailResponse.productDetails;
|
||||
_products.forEach((element) {
|
||||
ProductDetails product = element as ProductDetails;
|
||||
log("Product " + product.id + " " + product.price + " " + product.skuDetail.toString());
|
||||
});
|
||||
|
||||
final QueryPurchaseDetailsResponse purchaseResponse = await _connection.queryPastPurchases();
|
||||
if (purchaseResponse.error != null) {
|
||||
// handle query past purchase error..
|
||||
}
|
||||
|
||||
final List<PurchaseDetails> verifiedPurchases = [];
|
||||
for (PurchaseDetails purchase in purchaseResponse.pastPurchases) {
|
||||
if (await _verifyPurchase(purchase)) {
|
||||
verifiedPurchases.add(purchase);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO List<String> consumables = await ConsumableStore.load();
|
||||
_isAvailable = isAvailable;
|
||||
_products = productDetailResponse.productDetails;
|
||||
_purchases = verifiedPurchases;
|
||||
_notFoundIds = productDetailResponse.notFoundIDs;
|
||||
//_consumables = consumables;
|
||||
_purchasePending = false;
|
||||
}
|
||||
|
||||
// Platform messages are asynchronous, so we initialize in an async method.
|
||||
Future<void> initPurchasePlatform() async {
|
||||
if (_productList.length > 0) {
|
||||
return;
|
||||
}
|
||||
log(' --- InappPurchase connection: $_connection');
|
||||
log(" --- Init PurchasePlatform");
|
||||
await this.initStoreInfo();
|
||||
|
||||
Stream purchaseUpdated = InAppPurchaseConnection.instance.purchaseUpdatedStream;
|
||||
_subscription = purchaseUpdated.listen((purchaseDetailsList) {
|
||||
_listenToPurchaseUpdated(purchaseDetailsList);
|
||||
}, onDone: () {
|
||||
_subscription.cancel();
|
||||
}, onError: (error) {
|
||||
// handle error here.
|
||||
log("Error listen purchase updated " + error.toString());
|
||||
});
|
||||
}
|
||||
|
||||
void deliverProduct(PurchaseDetails purchaseDetails) async {
|
||||
log("DeliverProduct");
|
||||
// IMPORTANT!! Always verify a purchase purchase details before delivering the product.
|
||||
if (purchaseDetails.productID == _kConsumableId) {
|
||||
//TODO
|
||||
//await ConsumableStore.save(purchaseDetails.purchaseID);
|
||||
//List<String> consumables = await ConsumableStore.load();
|
||||
|
||||
_purchasePending = false;
|
||||
//_consumables = consumables;
|
||||
} else {
|
||||
_purchases.add(purchaseDetails);
|
||||
_purchasePending = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) {
|
||||
log("verifyPurchase");
|
||||
// IMPORTANT!! Always verify a purchase before delivering the product.
|
||||
// For the purpose of an example, we directly return true.
|
||||
log("Verifying Purchase" + purchaseDetails.toString());
|
||||
return Future<bool>.value(true);
|
||||
}
|
||||
|
||||
void _handleInvalidPurchase(PurchaseDetails purchaseDetails) {
|
||||
// handle invalid purchase here if _verifyPurchase` failed.
|
||||
log("Invalid Purchase" + purchaseDetails.toString());
|
||||
}
|
||||
|
||||
void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) {
|
||||
purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
|
||||
if (purchaseDetails.status == PurchaseStatus.pending) {
|
||||
//showPendingUI();
|
||||
log("Purchase pending");
|
||||
} else {
|
||||
if (purchaseDetails.status == PurchaseStatus.error) {
|
||||
//handleError(purchaseDetails.error);
|
||||
} else if (purchaseDetails.status == PurchaseStatus.purchased) {
|
||||
bool valid = await _verifyPurchase(purchaseDetails);
|
||||
if (valid) {
|
||||
deliverProduct(purchaseDetails);
|
||||
} else {
|
||||
_handleInvalidPurchase(purchaseDetails);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (Platform.isAndroid) {
|
||||
if (!_kAutoConsume && purchaseDetails.productID == _kConsumableId) {
|
||||
await InAppPurchaseConnection.instance.consumePurchase(purchaseDetails);
|
||||
}
|
||||
}
|
||||
if (purchaseDetails.pendingCompletePurchase) {
|
||||
await InAppPurchaseConnection.instance.completePurchase(purchaseDetails);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void getSubscriptions() {
|
||||
Cache().products.forEach((element) {
|
||||
Product product = element as Product;
|
||||
if (Platform.isAndroid) {
|
||||
if (product.productIdAndroid != null && product.productIdAndroid.isNotEmpty) {
|
||||
_productList.add(product.productIdAndroid);
|
||||
}
|
||||
} else {
|
||||
if (product.productIdIos != null && product.productIdIos.isNotEmpty) {
|
||||
_productList.add(product.productIdIos);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_productList.forEach((element) {
|
||||
print(element);
|
||||
});
|
||||
}
|
||||
|
||||
void purchase(Product product) {
|
||||
if (product == null) {
|
||||
throw Exception("No product to purchase");
|
||||
}
|
||||
String productId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos;
|
||||
ProductDetails productDetails;
|
||||
_products.forEach((element) {
|
||||
if (element.id == productId) {
|
||||
productDetails = element;
|
||||
log("product to purchase: " +
|
||||
productDetails.id +
|
||||
" title " +
|
||||
productDetails.title +
|
||||
" price " +
|
||||
productDetails.price +
|
||||
" period " +
|
||||
productDetails.skuDetail.subscriptionPeriod);
|
||||
}
|
||||
});
|
||||
|
||||
final PurchaseParam purchaseParam = PurchaseParam(productDetails: productDetails);
|
||||
/* if (_isConsumable(productDetails)) {
|
||||
InAppPurchaseConnection.instance.buyConsumable(purchaseParam: purchaseParam);
|
||||
} else { */
|
||||
InAppPurchaseConnection.instance.buyNonConsumable(purchaseParam: purchaseParam);
|
||||
//}
|
||||
// From here the purchase flow will be handled by the underlying storefront.
|
||||
// Updates will be delivered to the `InAppPurchaseConnection.instance.purchaseUpdatedStream`.
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -34,7 +34,8 @@ class RevenueCatPurchases with Logging {
|
||||
Future<void> restore() async {
|
||||
if (appUserId != null) {
|
||||
try {
|
||||
PurchaserInfo purchaserInfo = await Purchases.restoreTransactions();
|
||||
//PurchaserInfo purchaserInfo = await Purchases.restoreTransactions();
|
||||
PurchaserInfo purchaserInfo = await Purchases.getPurchaserInfo();
|
||||
if (purchaserInfo != null &&
|
||||
purchaserInfo.entitlements.all["wt_subscription"] != null &&
|
||||
purchaserInfo.entitlements.all["wt_subscription"].isActive) {
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:aitrainer_app/localization/app_language.dart';
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/main.dart';
|
||||
import 'package:aitrainer_app/util/app_language.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/service/api.dart';
|
||||
import 'package:aitrainer_app/service/logging.dart';
|
||||
import 'package:aitrainer_app/service/package_service.dart';
|
||||
import 'package:aitrainer_app/service/product_service.dart';
|
||||
import 'package:aitrainer_app/service/property_service.dart';
|
||||
import 'package:aitrainer_app/util/purchases.dart';
|
||||
import 'package:aitrainer_app/util/track.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import 'package:aitrainer_app/localization/app_localization.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
mixin Trans {
|
||||
|
||||
Reference in New Issue
Block a user