WT 1.1.13 Test Central bug fixes
This commit is contained in:
parent
4cde174a83
commit
cc1117d8a1
1
android/data/queries.sql
Normal file
1
android/data/queries.sql
Normal file
@ -0,0 +1 @@
|
||||
SELECT * FROM `tracking` WHERE `date_add` > '2021-04-17 00:00:00' AND `date_add` < '2021-04-18 00:00:00' AND `event` LIKE 'registration'
|
@ -439,6 +439,8 @@
|
||||
"How can serve you this result?":"How can serve you this result?",
|
||||
"Go":"Go",
|
||||
"Result":"Result",
|
||||
"Name too short":"Name too short"
|
||||
"Name too short":"Name too short",
|
||||
"No, bring me there":"No, bring me there",
|
||||
"You are about to add a new parallel test":"You are about to add a new parallel test"
|
||||
|
||||
}
|
@ -434,5 +434,7 @@
|
||||
"Development":"Fejlődésedhez",
|
||||
"Go":"Érdekel",
|
||||
"Result":"Értékelés",
|
||||
"Name too short":"A név túl rövid"
|
||||
"Name too short":"A név túl rövid",
|
||||
"No, bring me there":"Nem, vigyél oda",
|
||||
"You are about to add a new parallel test":"Egy új gyakorlatot készülsz párhuzamosan végrehajtani"
|
||||
}
|
@ -156,14 +156,14 @@ PODS:
|
||||
- path_provider (0.0.1):
|
||||
- Flutter
|
||||
- PromisesObjC (1.2.12)
|
||||
- Purchases (3.10.6):
|
||||
- PurchasesCoreSwift (= 3.10.6)
|
||||
- purchases_flutter (3.1.0):
|
||||
- Purchases (3.10.7):
|
||||
- PurchasesCoreSwift (= 3.10.7)
|
||||
- purchases_flutter (3.2.1):
|
||||
- Flutter
|
||||
- PurchasesHybridCommon (= 1.6.1)
|
||||
- PurchasesCoreSwift (3.10.6)
|
||||
- PurchasesHybridCommon (1.6.1):
|
||||
- Purchases (= 3.10.6)
|
||||
- PurchasesHybridCommon (= 1.6.2)
|
||||
- PurchasesCoreSwift (3.10.7)
|
||||
- PurchasesHybridCommon (1.6.2):
|
||||
- Purchases (= 3.10.7)
|
||||
- shared_preferences (0.0.1):
|
||||
- Flutter
|
||||
- smartlook (0.0.5):
|
||||
@ -312,10 +312,10 @@ SPEC CHECKSUMS:
|
||||
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
||||
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
|
||||
PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97
|
||||
Purchases: 520fdb59140fed96932a30d02a3ec04858cb541c
|
||||
purchases_flutter: 05472ba84c83f05a138a3a657f1013f5f7143539
|
||||
PurchasesCoreSwift: 31c2a3d7394432abbe64d46f0933835de0b33033
|
||||
PurchasesHybridCommon: 013c8072b73e752a206779747e88c068fbf999ec
|
||||
Purchases: b8b8fb6e856ac8166e217f6e014df894d821dda1
|
||||
purchases_flutter: 0130970b895c903e4e0aad793dd3a4c1b70bb434
|
||||
PurchasesCoreSwift: 8ae0f08e020f0bc97c1befa4e38a0dbc8e9732e0
|
||||
PurchasesHybridCommon: 5f5c1c245b12fc5e8760af7d11cb10f888109a9b
|
||||
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
|
||||
smartlook: bbc5c73a85c752a31dabf100c8930838c646342e
|
||||
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
|
||||
|
@ -405,7 +405,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.12;
|
||||
MARKETING_VERSION = 1.1.13;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -548,7 +548,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.12;
|
||||
MARKETING_VERSION = 1.1.13;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
@ -583,7 +583,7 @@
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.12;
|
||||
MARKETING_VERSION = 1.1.13;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.aitrainer.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
@ -136,7 +136,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
|
||||
}
|
||||
|
||||
product2Display.sort((a, b) {
|
||||
return a.sort < b.sort ? a.sort : b.sort;
|
||||
return a.sort < b.sort ? -1 : 1;
|
||||
});
|
||||
|
||||
productTest.productId = productId;
|
||||
|
@ -8,6 +8,7 @@ import 'package:aitrainer_app/model/exercise_plan.dart';
|
||||
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
||||
import 'package:aitrainer_app/model/exercise_plan_template.dart';
|
||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/repository/workout_tree_repository.dart';
|
||||
import 'package:aitrainer_app/service/exercise_plan_service.dart';
|
||||
import 'package:aitrainer_app/util/enums.dart';
|
||||
@ -28,6 +29,9 @@ class TestSetEditBloc extends Bloc<TestSetEditEvent, TestSetEditState> {
|
||||
final List<ExerciseType> _actualExerciseTypes = [];
|
||||
final HashMap<int, ExerciseType?> _exercisePlanDetails = HashMap();
|
||||
|
||||
final HashMap<int, List<ExerciseType>?> _displayPlanDetails = HashMap();
|
||||
int? sliderIndex;
|
||||
|
||||
TestSetEditBloc(
|
||||
{required this.templateName, required this.templateNameTranslation, required this.workoutTreeRepository, required this.menuBloc})
|
||||
: super(TestSetEditInitial()) {
|
||||
@ -36,12 +40,24 @@ class TestSetEditBloc extends Bloc<TestSetEditEvent, TestSetEditState> {
|
||||
final ExercisePlanTemplate template = element as ExercisePlanTemplate;
|
||||
if (template.name == templateName) {
|
||||
templateDescription = template.descriptionTranslation;
|
||||
int index = 0;
|
||||
template.exerciseTypes.forEach((id) {
|
||||
final ExerciseType? exerciseType = Cache().getExerciseTypeById(id);
|
||||
if (exerciseType != null) {
|
||||
_exerciseTypes.add(exerciseType);
|
||||
_actualExerciseTypes.add(exerciseType);
|
||||
_exercisePlanDetails[exerciseType.exerciseTypeId] = exerciseType;
|
||||
_exercisePlanDetails[index] = exerciseType;
|
||||
|
||||
_displayPlanDetails[index] = [exerciseType];
|
||||
final WorkoutMenuTree? workoutTree = menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseType.exerciseTypeId);
|
||||
final List<WorkoutMenuTree>? alternativeMenuItems = menuBloc.menuTreeRepository.getWorkoutTreeAlternatives(workoutTree);
|
||||
if (alternativeMenuItems != null) {
|
||||
final List<ExerciseType>? actualList = _displayPlanDetails[index];
|
||||
alternativeMenuItems.forEach((element) {
|
||||
actualList!.add(element.exerciseType!);
|
||||
});
|
||||
}
|
||||
index++;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -54,32 +70,24 @@ class TestSetEditBloc extends Bloc<TestSetEditEvent, TestSetEditState> {
|
||||
try {
|
||||
if (event is TestSetEditChangeExerciseType) {
|
||||
yield TestSetEditLoading();
|
||||
final List<ExerciseType> alternatives = workoutTreeRepository.getExerciseTypeAlternatives(event.exerciseTypeId);
|
||||
final ExerciseType? exerciseType = Cache().getExerciseTypeById(event.exerciseTypeId);
|
||||
if (exerciseType != null) {
|
||||
if (_exercisePlanDetails[event.exerciseTypeId] == null) {
|
||||
/// it was skipped
|
||||
_exercisePlanDetails[exerciseType.exerciseTypeId] = exerciseType;
|
||||
ExerciseType? exerciseType;
|
||||
if (_exercisePlanDetails[event.indexKey] == null) {
|
||||
exerciseType = displayPlanDetails[event.indexKey][0];
|
||||
} else {
|
||||
if (event.index == 0) {
|
||||
_exercisePlanDetails[exerciseType.exerciseTypeId] = exerciseType;
|
||||
} else {
|
||||
final changedExerciseType = alternatives[event.index - 1];
|
||||
_exercisePlanDetails[exerciseType.exerciseTypeId] = changedExerciseType;
|
||||
exerciseType = displayPlanDetails[event.indexKey][event.index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// to keep the slider accurate
|
||||
refreshActualPlan();
|
||||
_exercisePlanDetails[event.indexKey] = exerciseType;
|
||||
this.sliderIndex = event.index;
|
||||
yield TestSetEditReady();
|
||||
} else if (event is TestSetEditDeleteExerciseType) {
|
||||
yield TestSetEditLoading();
|
||||
final ExerciseType? exerciseType = Cache().getExerciseTypeById(event.exerciseTypeId);
|
||||
if (exerciseType != null) {
|
||||
_exercisePlanDetails[exerciseType.exerciseTypeId] = null;
|
||||
}
|
||||
refreshActualPlan();
|
||||
_exercisePlanDetails[event.indexKey] = null;
|
||||
|
||||
yield TestSetEditReady();
|
||||
} else if (event is TestSetEditAddExerciseType) {
|
||||
yield TestSetEditLoading();
|
||||
ExerciseType exerciseType = displayPlanDetails[event.indexKey][0];
|
||||
_exercisePlanDetails[event.indexKey] = exerciseType;
|
||||
yield TestSetEditReady();
|
||||
} else if (event is TestSetEditSubmit) {
|
||||
yield TestSetEditLoading();
|
||||
@ -114,6 +122,7 @@ class TestSetEditBloc extends Bloc<TestSetEditEvent, TestSetEditState> {
|
||||
List get exerciseTypes => this._exerciseTypes;
|
||||
List get actualExerciseTypes => this._actualExerciseTypes;
|
||||
HashMap get exercisePlanDetails => this._exercisePlanDetails;
|
||||
get displayPlanDetails => this._displayPlanDetails;
|
||||
|
||||
void refreshActualPlan() {
|
||||
_actualExerciseTypes.removeRange(0, _actualExerciseTypes.length - 1);
|
||||
|
@ -13,19 +13,27 @@ class TestSetEditLoad extends TestSetEditEvent {
|
||||
|
||||
class TestSetEditChangeExerciseType extends TestSetEditEvent {
|
||||
final int index;
|
||||
final int exerciseTypeId;
|
||||
const TestSetEditChangeExerciseType({required this.index, required this.exerciseTypeId});
|
||||
final int indexKey;
|
||||
const TestSetEditChangeExerciseType({required this.index, required this.indexKey});
|
||||
|
||||
@override
|
||||
List<Object> get props => [index, exerciseTypeId];
|
||||
List<Object> get props => [index, indexKey];
|
||||
}
|
||||
|
||||
class TestSetEditDeleteExerciseType extends TestSetEditEvent {
|
||||
final int exerciseTypeId;
|
||||
const TestSetEditDeleteExerciseType({required this.exerciseTypeId});
|
||||
final int indexKey;
|
||||
const TestSetEditDeleteExerciseType({required this.indexKey});
|
||||
|
||||
@override
|
||||
List<Object> get props => [exerciseTypeId];
|
||||
List<Object> get props => [indexKey];
|
||||
}
|
||||
|
||||
class TestSetEditAddExerciseType extends TestSetEditEvent {
|
||||
final int indexKey;
|
||||
const TestSetEditAddExerciseType({required this.indexKey});
|
||||
|
||||
@override
|
||||
List<Object> get props => [indexKey];
|
||||
}
|
||||
|
||||
class TestSetEditSkipExerciseType extends TestSetEditEvent {
|
||||
|
@ -37,6 +37,7 @@ class TestSetExecuteBloc extends Bloc<TestSetExecuteEvent, TestSetExecuteState>
|
||||
void initExercisePlan() {
|
||||
exercisePlan = Cache().activeExercisePlan;
|
||||
if (exercisePlan != null) {
|
||||
print("Ability ${exercisePlan!.type!}");
|
||||
testName = exercisePlan!.name;
|
||||
this.miniTestSet = exercisePlan!.type != null && ExerciseAbility.mini_test_set.equalsStringTo(exercisePlan!.type!);
|
||||
this.paralellTest = exercisePlan!.type != null && ExerciseAbility.paralell_test.equalsStringTo(exercisePlan!.type!);
|
||||
@ -265,7 +266,7 @@ class TestSetExecuteBloc extends Bloc<TestSetExecuteEvent, TestSetExecuteState>
|
||||
HashMap ret = HashMap();
|
||||
if (exercisePlan != null && ExerciseAbility.mini_test_set.equalsStringTo(exercisePlan!.type!)) {
|
||||
final String message = "You have an active Test Set!";
|
||||
final String message2 = "Do you want you to override it?";
|
||||
final String message2 = "Do you want to override it?";
|
||||
ret['message'] = message;
|
||||
ret['message2'] = message2;
|
||||
ret['canAdd'] = false;
|
||||
|
340
lib/library/facebook_app_events/facebook_app_events.dart
Normal file
340
lib/library/facebook_app_events/facebook_app_events.dart
Normal file
@ -0,0 +1,340 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
const channelName = 'flutter.oddbit.id/facebook_app_events';
|
||||
|
||||
class FacebookAppEvents {
|
||||
static const _channel = MethodChannel(channelName);
|
||||
|
||||
// See: https://github.com/facebook/facebook-android-sdk/blob/master/facebook-core/src/main/java/com/facebook/appevents/AppEventsConstants.java
|
||||
static const eventNameActivatedApp = 'fb_mobile_activate_app';
|
||||
static const eventNameDeactivatedApp = 'fb_mobile_deactivate_app';
|
||||
static const eventNameCompletedRegistration = 'fb_mobile_complete_registration';
|
||||
static const eventNameViewedContent = 'fb_mobile_content_view';
|
||||
static const eventNameRated = 'fb_mobile_rate';
|
||||
static const eventNameInitiatedCheckout = 'fb_mobile_initiated_checkout';
|
||||
static const eventNameAddedToCart = 'fb_mobile_add_to_cart';
|
||||
static const eventNameAddedToWishlist = 'fb_mobile_add_to_wishlist';
|
||||
|
||||
static const _paramNameValueToSum = "_valueToSum";
|
||||
static const paramNameCurrency = "fb_currency";
|
||||
static const paramNameRegistrationMethod = "fb_registration_method";
|
||||
static const paramNamePaymentInfoAvailable = "fb_payment_info_available";
|
||||
static const paramNameNumItems = "fb_num_items";
|
||||
static const paramValueYes = "1";
|
||||
static const paramValueNo = "0";
|
||||
|
||||
/// Parameter key used to specify a generic content type/family for the logged event, e.g.
|
||||
/// "music", "photo", "video". Options to use will vary depending on the nature of the app.
|
||||
static const paramNameContentType = "fb_content_type";
|
||||
|
||||
/// Parameter key used to specify data for the one or more pieces of content being logged about.
|
||||
/// Data should be a JSON encoded string.
|
||||
/// Example:
|
||||
/// "[{\"id\": \"1234\", \"quantity\": 2, \"item_price\": 5.99}, {\"id\": \"5678\", \"quantity\": 1, \"item_price\": 9.99}]"
|
||||
static const paramNameContent = "fb_content";
|
||||
|
||||
/// Parameter key used to specify an ID for the specific piece of content being logged about.
|
||||
/// This could be an EAN, article identifier, etc., depending on the nature of the app.
|
||||
static const paramNameContentId = "fb_content_id";
|
||||
|
||||
/// Clears the current user data
|
||||
Future<void> clearUserData() {
|
||||
return _channel.invokeMethod<void>('clearUserData');
|
||||
}
|
||||
|
||||
/// Clears the currently set user id.
|
||||
Future<void> clearUserID() {
|
||||
return _channel.invokeMethod<void>('clearUserID');
|
||||
}
|
||||
|
||||
/// Explicitly flush any stored events to the server.
|
||||
Future<void> flush() {
|
||||
return _channel.invokeMethod<void>('flush');
|
||||
}
|
||||
|
||||
/// Returns the app ID this logger was configured to log to.
|
||||
Future<String?> getApplicationId() {
|
||||
return _channel.invokeMethod<String>('getApplicationId');
|
||||
}
|
||||
|
||||
Future<String?> getAnonymousId() {
|
||||
return _channel.invokeMethod<String>('getAnonymousId');
|
||||
}
|
||||
|
||||
/// Log an app event with the specified [name] and the supplied [parameters] value.
|
||||
Future<void> logEvent({
|
||||
required String name,
|
||||
Map<String, dynamic>? parameters,
|
||||
double? valueToSum,
|
||||
}) {
|
||||
final args = <String, dynamic>{
|
||||
'name': name,
|
||||
'parameters': parameters,
|
||||
_paramNameValueToSum: valueToSum,
|
||||
};
|
||||
|
||||
return _channel.invokeMethod<void>('logEvent', _filterOutNulls(args));
|
||||
}
|
||||
|
||||
/// Sets user data to associate with all app events.
|
||||
/// All user data are hashed and used to match Facebook user from this
|
||||
/// instance of an application. The user data will be persisted between
|
||||
/// application instances.
|
||||
Future<void> setUserData({
|
||||
String? email,
|
||||
String? firstName,
|
||||
String? lastName,
|
||||
String? phone,
|
||||
String? dateOfBirth,
|
||||
String? gender,
|
||||
String? city,
|
||||
String? state,
|
||||
String? zip,
|
||||
String? country,
|
||||
}) {
|
||||
final args = <String, dynamic>{
|
||||
'email': email,
|
||||
'firstName': firstName,
|
||||
'lastName': lastName,
|
||||
'phone': phone,
|
||||
'dateOfBirth': dateOfBirth,
|
||||
'gender': gender,
|
||||
'city': city,
|
||||
'state': state,
|
||||
'zip': zip,
|
||||
'country': country,
|
||||
};
|
||||
|
||||
return _channel.invokeMethod<void>('setUserData', args);
|
||||
}
|
||||
|
||||
/// Logs an app event that tracks that the application was open via Push Notification.
|
||||
Future<void> logPushNotificationOpen({
|
||||
required Map<String, dynamic> payload,
|
||||
String? action,
|
||||
}) {
|
||||
final args = <String, dynamic>{
|
||||
'payload': payload,
|
||||
'action': action,
|
||||
};
|
||||
|
||||
return _channel.invokeMethod<void>('logPushNotificationOpen', args);
|
||||
}
|
||||
|
||||
/// Sets a user [id] to associate with all app events.
|
||||
/// This can be used to associate your own user id with the
|
||||
/// app events logged from this instance of an application.
|
||||
/// The user ID will be persisted between application instances.
|
||||
Future<void> setUserID(String id) {
|
||||
return _channel.invokeMethod<void>('setUserID', id);
|
||||
}
|
||||
|
||||
/// Update user properties as provided by a map of [parameters]
|
||||
Future<void> updateUserProperties({
|
||||
required Map<String, dynamic> parameters,
|
||||
String? applicationId,
|
||||
}) {
|
||||
final args = <String, dynamic>{
|
||||
'parameters': parameters,
|
||||
'applicationId': applicationId,
|
||||
};
|
||||
|
||||
return _channel.invokeMethod<void>('updateUserProperties', args);
|
||||
}
|
||||
|
||||
// Below are shorthand implementations of the predefined app event constants
|
||||
|
||||
/// Log this event when an app is being activated.
|
||||
///
|
||||
/// See: https://developers.facebook.com/docs/reference/androidsdk/current/facebook/com/facebook/appevents/appeventsconstants.html/#eventnameactivatedapp
|
||||
Future<void> logActivatedApp() {
|
||||
return logEvent(name: eventNameActivatedApp);
|
||||
}
|
||||
|
||||
/// Log this event when an app is being deactivated.
|
||||
///
|
||||
/// See: https://developers.facebook.com/docs/reference/androidsdk/current/facebook/com/facebook/appevents/appeventsconstants.html/#eventnamedeactivatedapp
|
||||
Future<void> logDeactivatedApp() {
|
||||
return logEvent(name: eventNameDeactivatedApp);
|
||||
}
|
||||
|
||||
/// Log this event when the user has completed registration with the app.
|
||||
/// Parameter [registrationMethod] is used to specify the method the user has
|
||||
/// used to register for the app, e.g. "Facebook", "email", "Google", etc.
|
||||
/// See: https://developers.facebook.com/docs/reference/androidsdk/current/facebook/com/facebook/appevents/appeventsconstants.html/#eventnamecompletedregistration
|
||||
Future<void> logCompletedRegistration({String? registrationMethod}) {
|
||||
return logEvent(
|
||||
name: eventNameCompletedRegistration,
|
||||
parameters: {
|
||||
paramNameRegistrationMethod: registrationMethod,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Log this event when the user has rated an item in the app.
|
||||
///
|
||||
/// See: https://developers.facebook.com/docs/reference/androidsdk/current/facebook/com/facebook/appevents/appeventsconstants.html/#eventnamerated
|
||||
Future<void> logRated({double? valueToSum}) {
|
||||
return logEvent(
|
||||
name: eventNameRated,
|
||||
valueToSum: valueToSum,
|
||||
);
|
||||
}
|
||||
|
||||
/// Log this event when the user has viewed a form of content in the app.
|
||||
///
|
||||
/// See: https://developers.facebook.com/docs/reference/androidsdk/current/facebook/com/facebook/appevents/appeventsconstants.html/#eventnameviewedcontent
|
||||
Future<void> logViewContent({
|
||||
Map<String, dynamic>? content,
|
||||
String? id,
|
||||
String? type,
|
||||
String? currency,
|
||||
double? price,
|
||||
}) {
|
||||
return logEvent(
|
||||
name: eventNameViewedContent,
|
||||
parameters: {
|
||||
paramNameContent: content != null ? json.encode(content) : null,
|
||||
paramNameContentId: id,
|
||||
paramNameContentType: type,
|
||||
paramNameCurrency: currency,
|
||||
},
|
||||
valueToSum: price,
|
||||
);
|
||||
}
|
||||
|
||||
/// Log this event when the user has added item to cart
|
||||
///
|
||||
/// See: https://developers.facebook.com/docs/reference/androidsdk/current/facebook/com/facebook/appevents/appeventsconstants.html/#eventnameaddedtocart
|
||||
Future<void> logAddToCart({
|
||||
Map<String, dynamic>? content,
|
||||
@required String? id,
|
||||
@required String? type,
|
||||
@required String? currency,
|
||||
@required double? price,
|
||||
}) {
|
||||
return logEvent(
|
||||
name: eventNameAddedToCart,
|
||||
parameters: {
|
||||
paramNameContent: content != null ? json.encode(content) : null,
|
||||
paramNameContentId: id,
|
||||
paramNameContentType: type,
|
||||
paramNameCurrency: currency,
|
||||
},
|
||||
valueToSum: price,
|
||||
);
|
||||
}
|
||||
|
||||
/// Log this event when the user has added item to cart
|
||||
///
|
||||
/// See: https://developers.facebook.com/docs/reference/androidsdk/current/facebook/com/facebook/appevents/appeventsconstants.html/#eventnameaddedtowishlist
|
||||
Future<void> logAddToWishlist({
|
||||
Map<String, dynamic>? content,
|
||||
@required String? id,
|
||||
@required String? type,
|
||||
@required String? currency,
|
||||
@required double? price,
|
||||
}) {
|
||||
return logEvent(
|
||||
name: eventNameAddedToWishlist,
|
||||
parameters: {
|
||||
paramNameContent: content != null ? json.encode(content) : null,
|
||||
paramNameContentId: id,
|
||||
paramNameContentType: type,
|
||||
paramNameCurrency: currency,
|
||||
},
|
||||
valueToSum: price,
|
||||
);
|
||||
}
|
||||
|
||||
/// Re-enables auto logging of app events after user consent
|
||||
/// if disabled for GDPR-compliance.
|
||||
///
|
||||
/// See: https://developers.facebook.com/docs/app-events/gdpr-compliance
|
||||
Future<void> setAutoLogAppEventsEnabled(bool enabled) {
|
||||
return _channel.invokeMethod<void>('setAutoLogAppEventsEnabled', enabled);
|
||||
}
|
||||
|
||||
/// Set Data Processing Options
|
||||
/// This is needed for California Consumer Privacy Act (CCPA) compliance
|
||||
///
|
||||
/// See: https://developers.facebook.com/docs/marketing-apis/data-processing-options
|
||||
Future<void> setDataProcessingOptions(
|
||||
List<String> options, {
|
||||
int? country,
|
||||
int? state,
|
||||
}) {
|
||||
final args = <String, dynamic>{
|
||||
'options': options,
|
||||
'country': country,
|
||||
'state': state,
|
||||
};
|
||||
|
||||
return _channel.invokeMethod<void>('setDataProcessingOptions', args);
|
||||
}
|
||||
|
||||
Future<void> logPurchase({
|
||||
required double amount,
|
||||
required String currency,
|
||||
Map<String, dynamic>? parameters,
|
||||
}) {
|
||||
final args = <String, dynamic>{
|
||||
'amount': amount,
|
||||
'currency': currency,
|
||||
'parameters': parameters,
|
||||
};
|
||||
return _channel.invokeMethod<void>('logPurchase', _filterOutNulls(args));
|
||||
}
|
||||
|
||||
Future<void> logInitiatedCheckout({
|
||||
required double totalPrice,
|
||||
required String currency,
|
||||
required String contentType,
|
||||
required String contentId,
|
||||
required int numItems,
|
||||
bool paymentInfoAvailable = false,
|
||||
}) {
|
||||
return logEvent(
|
||||
name: eventNameInitiatedCheckout,
|
||||
valueToSum: totalPrice,
|
||||
parameters: {
|
||||
paramNameContentType: contentType,
|
||||
paramNameContentId: contentId,
|
||||
paramNameNumItems: numItems,
|
||||
paramNameCurrency: currency,
|
||||
paramNamePaymentInfoAvailable: paymentInfoAvailable ? paramValueYes : paramValueNo,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Sets the Advert Tracking propeety for iOS advert tracking
|
||||
/// an iOS 14+ feature, android should just return a success.
|
||||
Future<void> setAdvertiserTracking({
|
||||
required bool enabled,
|
||||
}) {
|
||||
final args = <String, dynamic>{'enabled': enabled};
|
||||
|
||||
return _channel.invokeMethod<void>('setAdvertiserTracking', args);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ---------------------------------------------------------------------------
|
||||
//
|
||||
// PRIVATE METHODS BELOW HERE
|
||||
|
||||
/// Creates a new map containing all of the key/value pairs from [parameters]
|
||||
/// except those whose value is `null`.
|
||||
Map<String, dynamic> _filterOutNulls(Map<String, dynamic> parameters) {
|
||||
final Map<String, dynamic> filtered = <String, dynamic>{};
|
||||
parameters.forEach((String key, dynamic value) {
|
||||
if (value != null) {
|
||||
filtered[key] = value;
|
||||
}
|
||||
});
|
||||
return filtered;
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'wave.dart';
|
||||
|
||||
const double _twoPi = math.pi * 2.0;
|
||||
const double _epsilon = .001;
|
||||
const double _sweep = _twoPi - _epsilon;
|
||||
|
||||
class LiquidCircularProgressIndicator extends ProgressIndicator {
|
||||
///The width of the border, if this is set [borderColor] must also be set.
|
||||
final double borderWidth;
|
||||
|
||||
///The color of the border, if this is set [borderWidth] must also be set.
|
||||
final Color borderColor;
|
||||
|
||||
///The widget to show in the center of the progress indicator.
|
||||
final Widget? center;
|
||||
|
||||
///The direction the liquid travels.
|
||||
final Axis direction;
|
||||
|
||||
LiquidCircularProgressIndicator({
|
||||
Key? key,
|
||||
double value = 0.5,
|
||||
Color? backgroundColor,
|
||||
Animation<Color>? valueColor,
|
||||
required this.borderWidth,
|
||||
required this.borderColor,
|
||||
this.center,
|
||||
this.direction = Axis.vertical,
|
||||
}) : super(
|
||||
key: key,
|
||||
value: value,
|
||||
backgroundColor: backgroundColor,
|
||||
valueColor: valueColor,
|
||||
);
|
||||
|
||||
Color _getBackgroundColor(BuildContext context) => backgroundColor ?? Theme.of(context).backgroundColor;
|
||||
|
||||
Color _getValueColor(BuildContext context) => valueColor?.value ?? Theme.of(context).accentColor;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _LiquidCircularProgressIndicatorState();
|
||||
}
|
||||
|
||||
class _LiquidCircularProgressIndicatorState extends State<LiquidCircularProgressIndicator> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipPath(
|
||||
clipper: _CircleClipper(),
|
||||
child: CustomPaint(
|
||||
painter: _CirclePainter(
|
||||
color: widget._getBackgroundColor(context),
|
||||
),
|
||||
foregroundPainter: _CircleBorderPainter(
|
||||
color: widget.borderColor,
|
||||
width: widget.borderWidth,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Wave(
|
||||
value: widget.value!,
|
||||
color: widget._getValueColor(context),
|
||||
direction: widget.direction,
|
||||
),
|
||||
if (widget.center != null) Center(child: widget.center),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CirclePainter extends CustomPainter {
|
||||
final Color color;
|
||||
|
||||
_CirclePainter({required this.color});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()..color = color;
|
||||
canvas.drawArc(Offset.zero & size, 0, _sweep, false, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_CirclePainter oldDelegate) => color != oldDelegate.color;
|
||||
}
|
||||
|
||||
class _CircleBorderPainter extends CustomPainter {
|
||||
final Color color;
|
||||
final double width;
|
||||
|
||||
_CircleBorderPainter({required this.color, required this.width});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final borderPaint = Paint()
|
||||
..color = color
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = width;
|
||||
final newSize = Size(size.width - width, size.height - width);
|
||||
canvas.drawArc(Offset(width / 2, width / 2) & newSize, 0, _sweep, false, borderPaint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_CircleBorderPainter oldDelegate) => color != oldDelegate.color || width != oldDelegate.width;
|
||||
}
|
||||
|
||||
class _CircleClipper extends CustomClipper<Path> {
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
final path = Path()..addArc(Offset.zero & size, 0, _sweep);
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'wave.dart';
|
||||
|
||||
class LiquidCustomProgressIndicator extends ProgressIndicator {
|
||||
///The widget to show in the center of the progress indicator.
|
||||
final Widget? center;
|
||||
|
||||
///The direction the liquid travels.
|
||||
final Axis direction;
|
||||
|
||||
///The path used to draw the shape of the progress indicator. The size of the progress indicator is controlled by the bounds of this path.
|
||||
final Path shapePath;
|
||||
|
||||
LiquidCustomProgressIndicator({
|
||||
Key? key,
|
||||
double value = 0.5,
|
||||
Color? backgroundColor,
|
||||
Animation<Color>? valueColor,
|
||||
this.center,
|
||||
required this.direction,
|
||||
required this.shapePath,
|
||||
}) : super(
|
||||
key: key,
|
||||
value: value,
|
||||
backgroundColor: backgroundColor,
|
||||
valueColor: valueColor,
|
||||
);
|
||||
|
||||
Color _getBackgroundColor(BuildContext context) => backgroundColor ?? Theme.of(context).backgroundColor;
|
||||
|
||||
Color _getValueColor(BuildContext context) => valueColor?.value ?? Theme.of(context).accentColor;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _LiquidCustomProgressIndicatorState();
|
||||
}
|
||||
|
||||
class _LiquidCustomProgressIndicatorState extends State<LiquidCustomProgressIndicator> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final pathBounds = widget.shapePath.getBounds();
|
||||
return SizedBox(
|
||||
width: pathBounds.width + pathBounds.left,
|
||||
height: pathBounds.height + pathBounds.top,
|
||||
child: ClipPath(
|
||||
clipper: _CustomPathClipper(
|
||||
path: widget.shapePath,
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter: _CustomPathPainter(
|
||||
color: widget._getBackgroundColor(context),
|
||||
path: widget.shapePath,
|
||||
),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Positioned.fill(
|
||||
left: pathBounds.left,
|
||||
top: pathBounds.top,
|
||||
child: Wave(
|
||||
value: widget.value!,
|
||||
color: widget._getValueColor(context),
|
||||
direction: widget.direction,
|
||||
),
|
||||
),
|
||||
if (widget.center != null) Center(child: widget.center),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CustomPathPainter extends CustomPainter {
|
||||
final Color color;
|
||||
final Path path;
|
||||
|
||||
_CustomPathPainter({required this.color, required this.path});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()..color = color;
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_CustomPathPainter oldDelegate) => color != oldDelegate.color || path != oldDelegate.path;
|
||||
}
|
||||
|
||||
class _CustomPathClipper extends CustomClipper<Path> {
|
||||
final Path path;
|
||||
|
||||
_CustomPathClipper({required this.path});
|
||||
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'wave.dart';
|
||||
|
||||
class LiquidLinearProgressIndicator extends ProgressIndicator {
|
||||
///The width of the border, if this is set [borderColor] must also be set.
|
||||
final double? borderWidth;
|
||||
|
||||
///The color of the border, if this is set [borderWidth] must also be set.
|
||||
final Color? borderColor;
|
||||
|
||||
///The radius of the border.
|
||||
final double? borderRadius;
|
||||
|
||||
///The widget to show in the center of the progress indicator.
|
||||
final Widget? center;
|
||||
|
||||
///The direction the liquid travels.
|
||||
final Axis direction;
|
||||
|
||||
LiquidLinearProgressIndicator({
|
||||
Key? key,
|
||||
double value = 0.5,
|
||||
Color? backgroundColor,
|
||||
Animation<Color>? valueColor,
|
||||
this.borderWidth,
|
||||
this.borderColor,
|
||||
this.borderRadius,
|
||||
this.center,
|
||||
this.direction = Axis.horizontal,
|
||||
}) : super(
|
||||
key: key,
|
||||
value: value,
|
||||
backgroundColor: backgroundColor,
|
||||
valueColor: valueColor,
|
||||
) {
|
||||
if (borderWidth != null && borderColor == null || borderColor != null && borderWidth == null) {
|
||||
throw ArgumentError("borderWidth and borderColor should both be set.");
|
||||
}
|
||||
}
|
||||
|
||||
Color _getBackgroundColor(BuildContext context) => backgroundColor ?? Theme.of(context).backgroundColor;
|
||||
|
||||
Color _getValueColor(BuildContext context) => valueColor?.value ?? Theme.of(context).accentColor;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _LiquidLinearProgressIndicatorState();
|
||||
}
|
||||
|
||||
class _LiquidLinearProgressIndicatorState extends State<LiquidLinearProgressIndicator> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipPath(
|
||||
clipper: _LinearClipper(
|
||||
radius: widget.borderRadius!,
|
||||
),
|
||||
child: CustomPaint(
|
||||
painter: _LinearPainter(
|
||||
color: widget._getBackgroundColor(context),
|
||||
radius: widget.borderRadius!,
|
||||
),
|
||||
foregroundPainter: _LinearBorderPainter(
|
||||
color: widget.borderColor!,
|
||||
width: widget.borderWidth!,
|
||||
radius: widget.borderRadius!,
|
||||
),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Wave(
|
||||
value: widget.value!,
|
||||
color: widget._getValueColor(context),
|
||||
direction: widget.direction,
|
||||
),
|
||||
if (widget.center != null) Center(child: widget.center),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _LinearPainter extends CustomPainter {
|
||||
final Color color;
|
||||
final double radius;
|
||||
|
||||
_LinearPainter({required this.color, required this.radius});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()..color = color;
|
||||
canvas.drawRRect(
|
||||
RRect.fromRectAndRadius(
|
||||
Rect.fromLTWH(0, 0, size.width, size.height),
|
||||
Radius.circular(radius),
|
||||
),
|
||||
paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_LinearPainter oldDelegate) => color != oldDelegate.color;
|
||||
}
|
||||
|
||||
class _LinearBorderPainter extends CustomPainter {
|
||||
final Color color;
|
||||
final double width;
|
||||
final double? radius;
|
||||
|
||||
_LinearBorderPainter({
|
||||
required this.color,
|
||||
required this.width,
|
||||
required this.radius,
|
||||
});
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final paint = Paint()
|
||||
..color = color
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = width;
|
||||
final alteredRadius = radius ?? 0;
|
||||
canvas.drawRRect(
|
||||
RRect.fromRectAndRadius(
|
||||
Rect.fromLTWH(width / 2, width / 2, size.width - width, size.height - width),
|
||||
Radius.circular(alteredRadius - width),
|
||||
),
|
||||
paint);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_LinearBorderPainter oldDelegate) =>
|
||||
color != oldDelegate.color || width != oldDelegate.width || radius != oldDelegate.radius;
|
||||
}
|
||||
|
||||
class _LinearClipper extends CustomClipper<Path> {
|
||||
final double? radius;
|
||||
|
||||
_LinearClipper({required this.radius});
|
||||
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
final path = Path()
|
||||
..addRRect(
|
||||
RRect.fromRectAndRadius(
|
||||
Rect.fromLTWH(0, 0, size.width, size.height),
|
||||
Radius.circular(radius ?? 0),
|
||||
),
|
||||
);
|
||||
return path;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(CustomClipper<Path> oldClipper) => false;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
library liquid_progress_indicator;
|
||||
|
||||
export 'liquid_circular_progress_indicator.dart';
|
||||
//export 'liquid_linear_progress_indicator.dart';
|
||||
//export 'liquid_custom_progress_indicator.dart';
|
114
lib/library/liquid_progress_indicator/wave.dart
Normal file
114
lib/library/liquid_progress_indicator/wave.dart
Normal file
@ -0,0 +1,114 @@
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Wave extends StatefulWidget {
|
||||
final double value;
|
||||
final Color color;
|
||||
final Axis direction;
|
||||
|
||||
const Wave({
|
||||
Key? key,
|
||||
required this.value,
|
||||
required this.color,
|
||||
required this.direction,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_WaveState createState() => _WaveState();
|
||||
}
|
||||
|
||||
class _WaveState extends State<Wave> with SingleTickerProviderStateMixin {
|
||||
late AnimationController _animationController;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_animationController = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(seconds: 2),
|
||||
);
|
||||
_animationController.repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: CurvedAnimation(
|
||||
parent: _animationController,
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
builder: (context, child) => ClipPath(
|
||||
child: Container(
|
||||
color: widget.color,
|
||||
),
|
||||
clipper: _WaveClipper(
|
||||
animationValue: _animationController.value,
|
||||
value: widget.value,
|
||||
direction: widget.direction,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _WaveClipper extends CustomClipper<Path> {
|
||||
final double animationValue;
|
||||
final double value;
|
||||
final Axis direction;
|
||||
|
||||
_WaveClipper({
|
||||
required this.animationValue,
|
||||
required this.value,
|
||||
required this.direction,
|
||||
});
|
||||
|
||||
@override
|
||||
Path getClip(Size size) {
|
||||
if (direction == Axis.horizontal) {
|
||||
Path path = Path()
|
||||
..addPolygon(_generateHorizontalWavePath(size), false)
|
||||
..lineTo(0.0, size.height)
|
||||
..lineTo(0.0, 0.0)
|
||||
..close();
|
||||
return path;
|
||||
}
|
||||
|
||||
Path path = Path()
|
||||
..addPolygon(_generateVerticalWavePath(size), false)
|
||||
..lineTo(size.width, size.height)
|
||||
..lineTo(0.0, size.height)
|
||||
..close();
|
||||
return path;
|
||||
}
|
||||
|
||||
List<Offset> _generateHorizontalWavePath(Size size) {
|
||||
final waveList = <Offset>[];
|
||||
for (int i = -2; i <= size.height.toInt() + 2; i++) {
|
||||
final waveHeight = (size.width / 20);
|
||||
final dx = math.sin((animationValue * 360 - i) % 360 * (math.pi / 180)) * waveHeight + (size.width * value);
|
||||
waveList.add(Offset(dx, i.toDouble()));
|
||||
}
|
||||
return waveList;
|
||||
}
|
||||
|
||||
List<Offset> _generateVerticalWavePath(Size size) {
|
||||
final waveList = <Offset>[];
|
||||
for (int i = -2; i <= size.width.toInt() + 2; i++) {
|
||||
final waveHeight = (size.height / 20);
|
||||
final dy = math.sin((animationValue * 360 - i) % 360 * (math.pi / 180)) * waveHeight + (size.height - (size.height * value));
|
||||
waveList.add(Offset(i.toDouble(), dy));
|
||||
}
|
||||
return waveList;
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldReclip(_WaveClipper oldClipper) => animationValue != oldClipper.animationValue;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart';
|
||||
import 'package:aitrainer_app/push_notifications.dart';
|
||||
import 'package:aitrainer_app/repository/customer_repository.dart';
|
||||
@ -35,6 +36,7 @@ import 'package:aitrainer_app/view/test_set_edit.dart';
|
||||
import 'package:aitrainer_app/view/test_set_execute.dart';
|
||||
import 'package:aitrainer_app/view/test_set_new.dart';
|
||||
import 'package:aitrainer_app/widgets/home.dart';
|
||||
import 'package:aitrainer_app/library/facebook_app_events/facebook_app_events.dart';
|
||||
import 'package:firebase_analytics/firebase_analytics.dart';
|
||||
import 'package:firebase_analytics/observer.dart';
|
||||
import 'package:flurry/flurry.dart';
|
||||
@ -56,6 +58,7 @@ import 'bloc/menu/menu_bloc.dart';
|
||||
import 'bloc/session/session_bloc.dart';
|
||||
import 'bloc/settings/settings_bloc.dart';
|
||||
import 'bloc/timer/timer_bloc.dart';
|
||||
import 'model/cache.dart';
|
||||
|
||||
const dsn = 'https://5fac40cbfcfb4c15aa80c7a8638d7310@o418565.ingest.sentry.io/5322520';
|
||||
|
||||
@ -84,11 +87,11 @@ Future<Null> _reportError(dynamic error, dynamic stackTrace) async {
|
||||
}
|
||||
|
||||
print('Reporting to Sentry.io...');
|
||||
|
||||
final sentryId = await Sentry.captureException(
|
||||
error,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
final String customerId = Cache().userLoggedIn != null ? Cache().userLoggedIn!.customerId.toString() : "0";
|
||||
final String platform = Platform.isAndroid ? "Android" : "iOS";
|
||||
final String version = Cache().packageInfo != null ? Cache().packageInfo!.version + "+" + Cache().packageInfo!.buildNumber : "";
|
||||
final sentryId =
|
||||
await Sentry.captureException(error, stackTrace: stackTrace, hint: "Platform: $platform, Version: $version, User: $customerId");
|
||||
|
||||
print('Capture exception result : SentryId : $sentryId');
|
||||
}
|
||||
@ -185,10 +188,12 @@ Future<void> initFlurry() async {
|
||||
}
|
||||
|
||||
class WorkoutTestApp extends StatelessWidget {
|
||||
static final facebookAppEvents = FacebookAppEvents();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
||||
final FirebaseAnalytics analytics = FirebaseAnalytics();
|
||||
//facebookAppEvents.setAdvertiserTracking(enabled: true);
|
||||
initFlurry();
|
||||
PushNotificationsManager().init();
|
||||
return MaterialApp(
|
||||
|
@ -191,6 +191,7 @@ class Cache with Logging {
|
||||
DateTime savedPlanDate;
|
||||
|
||||
savedPlanDate = format.parse(savedPlanDateString);
|
||||
print("Saved plan: $savedPlanDate");
|
||||
|
||||
final DateTime now = DateTime.now();
|
||||
final DateTime added = savedPlanDate.add(Duration(days: 1));
|
||||
|
@ -3,7 +3,7 @@ enum ExerciseAbility { oneRepMax, endurance, running, mini_test_set, paralell_te
|
||||
extension ExerciseAbilityExt on ExerciseAbility {
|
||||
String enumToString() => this.toString().split(".").last;
|
||||
bool equalsTo(ExerciseAbility ability) => this.toString() == ability.toString();
|
||||
bool equalsStringTo(String ability) => this.toString() == ability;
|
||||
bool equalsStringTo(String ability) => this.enumToString() == ability;
|
||||
String get description {
|
||||
switch (this) {
|
||||
case ExerciseAbility.endurance:
|
||||
|
@ -22,7 +22,14 @@ class ExercisePlanTemplate {
|
||||
}
|
||||
|
||||
if (json['details'] != null && (json['details']).length > 0) {
|
||||
List details = json['details'];
|
||||
final List details = json['details'];
|
||||
details.sort((a, b) {
|
||||
if (a['sort'] == null || b['sort'] == null) {
|
||||
return a['exercisePlanTemplateDetailId'] < b['exercisePlanTemplateDetailId'] ? -1 : 1;
|
||||
} else {
|
||||
return a['sort'] < b['sort'] ? -1 : 1;
|
||||
}
|
||||
});
|
||||
details.forEach((element) {
|
||||
exerciseTypes.add(element['exerciseTypeId']);
|
||||
});
|
||||
|
@ -138,4 +138,8 @@ mixin Common {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static normalizeDecimal(String value) {
|
||||
return value.replaceFirst(",", ".");
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import 'package:aitrainer_app/widgets/dialog_html.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:liquid_progress_indicator/liquid_progress_indicator.dart';
|
||||
import 'package:aitrainer_app/library/liquid_progress_indicator/liquid_custom_progress_indicator.dart';
|
||||
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
|
||||
import 'package:rainbow_color/rainbow_color.dart';
|
||||
|
||||
@ -598,9 +598,9 @@ class _AnimatedLiquidCustomProgressIndicatorState extends State<_AnimatedLiquidC
|
||||
vsync: this,
|
||||
duration: Duration(seconds: 3),
|
||||
)..addListener(() {
|
||||
setState(() {
|
||||
/* setState(() {
|
||||
print("build animation state change");
|
||||
});
|
||||
}); */
|
||||
});
|
||||
|
||||
_animationController.forward();
|
||||
@ -608,7 +608,7 @@ class _AnimatedLiquidCustomProgressIndicatorState extends State<_AnimatedLiquidC
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
buildAnimation();
|
||||
//buildAnimation();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
import '../bloc/customer_change/customer_change_bloc.dart';
|
||||
import '../library/dropdown_search.dart';
|
||||
import '../library/dropdown_search/dropdown_search.dart';
|
||||
|
||||
// ignore: must_be_immutable
|
||||
class CustomerFitnessPage extends StatefulWidget {
|
||||
|
@ -136,7 +136,7 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
|
||||
final bool weightVisible = bloc.exercisePlanRepository.getActualPlanDetail()!.exerciseType!.unitQuantityUnit != null;
|
||||
String summary = bloc.serie!.toStringAsFixed(0) + " x " + bloc.quantity.toStringAsFixed(0);
|
||||
if (bloc.quantityUnit > 0) {
|
||||
summary += " x " + bloc.quantityUnit.toStringAsFixed(0) + " kg";
|
||||
summary += " x " + bloc.quantityUnit.toStringAsFixed(1) + " kg";
|
||||
}
|
||||
final String unit = bloc.exercisePlanRepository.getActualPlanDetail()!.exerciseType!.unit;
|
||||
return Form(
|
||||
@ -237,11 +237,15 @@ class _ExercisePlanDetailAddPage extends State<ExercisePlanDetailAddPage> with T
|
||||
),
|
||||
),
|
||||
focusNode: _nodeText3,
|
||||
initialValue: bloc.quantityUnit.toStringAsFixed(0),
|
||||
initialValue: bloc.quantityUnit.toStringAsFixed(1),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
style: GoogleFonts.archivoBlack(fontSize: 60, color: Colors.yellow[200]),
|
||||
onChanged: (value) => {
|
||||
if (value.isNotEmpty) {bloc.add(ExercisePlanCustomAddChangeQuantityUnit(quantity: double.parse(value)))}
|
||||
if (value.isNotEmpty)
|
||||
{
|
||||
value = value.replaceFirst(",", "."),
|
||||
bloc.add(ExercisePlanCustomAddChangeQuantityUnit(quantity: double.parse(value)))
|
||||
}
|
||||
})
|
||||
: Offstage(),
|
||||
|
||||
|
@ -3,6 +3,7 @@ import 'dart:collection';
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/test_set_edit/test_set_edit_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_type.dart';
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
@ -10,6 +11,7 @@ import 'package:aitrainer_app/widgets/app_bar.dart';
|
||||
import 'package:aitrainer_app/widgets/dialog_common.dart';
|
||||
import 'package:aitrainer_app/widgets/menu_image.dart';
|
||||
import 'package:carousel_slider/carousel_slider.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
@ -25,6 +27,7 @@ class TestSetEdit extends StatelessWidget with Trans {
|
||||
// ignore: close_sinks
|
||||
final MenuBloc menuBloc = BlocProvider.of<MenuBloc>(context);
|
||||
late TestSetEditBloc? bloc;
|
||||
final bool activeExercisePlan = Cache().activeExercisePlan != null;
|
||||
|
||||
setContext(context);
|
||||
return Scaffold(
|
||||
@ -65,7 +68,51 @@ class TestSetEdit extends StatelessWidget with Trans {
|
||||
);
|
||||
}))),
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
onPressed: () => showDialog(
|
||||
onPressed: () {
|
||||
if (activeExercisePlan) {
|
||||
showCupertinoDialog(
|
||||
useRootNavigator: true,
|
||||
context: context,
|
||||
builder: (_) => CupertinoAlertDialog(
|
||||
title: Text(t("You have an active Test Set!") + "\n" + Cache().activeExercisePlan!.name),
|
||||
content: Column(children: [
|
||||
Divider(),
|
||||
Text(t("Do you want to override it?"), style: GoogleFonts.inter(color: Colors.black, fontSize: 16)),
|
||||
]),
|
||||
actions: [
|
||||
TextButton(
|
||||
child: Text(t("No, bring me there"), textAlign: TextAlign.center),
|
||||
onPressed: () => {
|
||||
Navigator.pop(context),
|
||||
Navigator.pop(context),
|
||||
Navigator.of(context).pushNamed("testSetExecute"),
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(t("Yes")),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
startTrainingDialog(bloc);
|
||||
},
|
||||
)
|
||||
],
|
||||
));
|
||||
} else {
|
||||
startTrainingDialog(bloc);
|
||||
}
|
||||
},
|
||||
backgroundColor: Colors.orange[800],
|
||||
icon: Icon(CustomIcon.clock),
|
||||
label: Text(
|
||||
t("Start training"),
|
||||
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void startTrainingDialog(TestSetEditBloc? bloc) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
@ -77,20 +124,12 @@ class TestSetEdit extends StatelessWidget with Trans {
|
||||
Navigator.of(context).pop(),
|
||||
if (bloc != null)
|
||||
{
|
||||
bloc!.add(TestSetEditSubmit()),
|
||||
bloc.add(TestSetEditSubmit()),
|
||||
}
|
||||
},
|
||||
onCancel: () => {Navigator.of(context).pop()},
|
||||
);
|
||||
}),
|
||||
backgroundColor: Colors.orange[800],
|
||||
icon: Icon(CustomIcon.clock),
|
||||
label: Text(
|
||||
t("Start training"),
|
||||
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget getTestSetWidget(TestSetEditBloc bloc, String templateName) {
|
||||
@ -155,61 +194,44 @@ class TestSetEdit extends StatelessWidget with Trans {
|
||||
]));
|
||||
}
|
||||
|
||||
List<Widget> imageSliders(List<WorkoutMenuTree> alternatives, MenuBloc menuBloc, WorkoutMenuTree workoutTree, TestSetEditBloc bloc) {
|
||||
List<Widget> imageSliders(int index, WorkoutMenuTree? workoutTree, TestSetEditBloc bloc) {
|
||||
final List<Widget> list = [];
|
||||
if (bloc.exercisePlanDetails[workoutTree.exerciseTypeId] == null) {
|
||||
list.add(Container(
|
||||
padding: EdgeInsets.only(top: 25, bottom: 25),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: Container(
|
||||
color: Colors.red[600],
|
||||
child: Center(
|
||||
child: Text(
|
||||
"X",
|
||||
style: GoogleFonts.archivoBlack(
|
||||
color: Colors.white,
|
||||
fontSize: 80,
|
||||
),
|
||||
),
|
||||
)))));
|
||||
list.add(getImageStack(workoutTree, menuBloc, bloc));
|
||||
} else {
|
||||
ExerciseType exerciseType = bloc.exercisePlanDetails[workoutTree.exerciseTypeId];
|
||||
bool deleted = workoutTree == null;
|
||||
bloc.displayPlanDetails[index].forEach((value) {
|
||||
ExerciseType alternative = value;
|
||||
|
||||
final WorkoutMenuTree actualWorkoutTree = bloc.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(exerciseType.exerciseTypeId)!;
|
||||
list.add(getImageStack(actualWorkoutTree, menuBloc, bloc));
|
||||
}
|
||||
final WorkoutMenuTree? workoutTreeAlternative =
|
||||
bloc.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(alternative.exerciseTypeId);
|
||||
|
||||
alternatives.forEach((element) {
|
||||
if (workoutTree.exerciseTypeId != element.exerciseTypeId) {
|
||||
list.add(getImageStack(element, menuBloc, bloc));
|
||||
}
|
||||
list.add(getImageStack(workoutTreeAlternative!, bloc, index, deleted));
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
Stack getImageStack(WorkoutMenuTree element, MenuBloc menuBloc, TestSetEditBloc bloc) {
|
||||
Stack getImageStack(WorkoutMenuTree element, TestSetEditBloc bloc, int index, bool deleted) {
|
||||
return Stack(alignment: Alignment.topRight, children: [
|
||||
Stack(alignment: Alignment.bottomLeft, children: [
|
||||
MenuImage(imageName: element.imageName, workoutTreeId: element.id),
|
||||
deleted
|
||||
? Opacity(opacity: 0.2, child: MenuImage(imageName: element.imageName, workoutTreeId: element.id))
|
||||
: MenuImage(imageName: element.imageName, workoutTreeId: element.id),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 15, bottom: 15, right: 15),
|
||||
child: Text(
|
||||
element.name,
|
||||
maxLines: 4,
|
||||
style: GoogleFonts.archivoBlack(color: element.color, fontSize: 16, height: 1.1),
|
||||
style: GoogleFonts.archivoBlack(color: deleted ? element.color.withOpacity(0.2) : element.color, fontSize: 16, height: 1.1),
|
||||
),
|
||||
),
|
||||
]),
|
||||
Container(
|
||||
deleted == false
|
||||
? Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: GestureDetector(
|
||||
onTap: () => bloc.add(TestSetEditDeleteExerciseType(exerciseTypeId: element.exerciseTypeId)),
|
||||
onTap: () => bloc.add(TestSetEditDeleteExerciseType(indexKey: index)),
|
||||
child: Container(
|
||||
color: Colors.red[600],
|
||||
child: Center(
|
||||
@ -221,16 +243,33 @@ class TestSetEdit extends StatelessWidget with Trans {
|
||||
),
|
||||
),
|
||||
)))))
|
||||
: Container(
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(24.0),
|
||||
child: GestureDetector(
|
||||
onTap: () => bloc.add(TestSetEditAddExerciseType(indexKey: index)),
|
||||
child: Container(
|
||||
color: Colors.yellow[700],
|
||||
child: Center(
|
||||
child: Icon(
|
||||
Icons.undo_sharp,
|
||||
size: 40,
|
||||
color: Colors.white,
|
||||
)),
|
||||
))))
|
||||
]);
|
||||
}
|
||||
|
||||
List<Widget> getExerciseTypeWidgets(TestSetEditBloc bloc) {
|
||||
final List<Widget> widgets = [];
|
||||
bloc.exerciseTypes.forEach((element) {
|
||||
final WorkoutMenuTree? workoutTree = bloc.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(element.exerciseTypeId);
|
||||
bloc.exercisePlanDetails.forEach((key, element) {
|
||||
WorkoutMenuTree? workoutTree;
|
||||
if (element != null) {
|
||||
workoutTree = bloc.menuBloc.menuTreeRepository.getMenuItemByExerciseTypeId(element.exerciseTypeId);
|
||||
}
|
||||
|
||||
final List<WorkoutMenuTree>? alternativeMenuItems = bloc.menuBloc.menuTreeRepository.getWorkoutTreeAlternatives(workoutTree);
|
||||
if (workoutTree != null && alternativeMenuItems != null) {
|
||||
final Widget widget = CarouselSlider(
|
||||
options: CarouselOptions(
|
||||
viewportFraction: 0.80,
|
||||
@ -239,13 +278,11 @@ class TestSetEdit extends StatelessWidget with Trans {
|
||||
autoPlay: false,
|
||||
aspectRatio: 2,
|
||||
enlargeCenterPage: true,
|
||||
onPageChanged: (index, reason) =>
|
||||
bloc.add(TestSetEditChangeExerciseType(index: index, exerciseTypeId: element.exerciseTypeId)),
|
||||
onPageChanged: (index, reason) => bloc.add(TestSetEditChangeExerciseType(index: index, indexKey: key)),
|
||||
enlargeStrategy: CenterPageEnlargeStrategy.scale),
|
||||
items: imageSliders(alternativeMenuItems, bloc.menuBloc, workoutTree, bloc),
|
||||
items: imageSliders(key, workoutTree, bloc),
|
||||
);
|
||||
widgets.add(widget);
|
||||
}
|
||||
});
|
||||
return widgets;
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import 'dart:collection';
|
||||
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
|
||||
import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_bloc.dart';
|
||||
import 'package:aitrainer_app/library/custom_icon_icons.dart';
|
||||
import 'package:aitrainer_app/library/fade_in.dart';
|
||||
import 'package:aitrainer_app/model/cache.dart';
|
||||
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
|
||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||
@ -32,7 +31,7 @@ class TestSetExecute extends StatelessWidget with Trans {
|
||||
executeBloc.add(TestSetExecuteLoad());
|
||||
setContext(context);
|
||||
return Scaffold(
|
||||
appBar: AppBarNav(depth: 1),
|
||||
appBar: AppBarNav(depth: 0),
|
||||
body: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
@ -349,11 +348,7 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
|
||||
void initState() {
|
||||
animation.start();
|
||||
animation.addStatusListener((status) {
|
||||
if (status == AnimationStatus.completed) {
|
||||
setState(() {
|
||||
print("animation state completed");
|
||||
});
|
||||
}
|
||||
if (status == AnimationStatus.completed) {}
|
||||
});
|
||||
|
||||
super.initState();
|
||||
@ -407,7 +402,6 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
|
||||
final bool done = state.equalsTo(ExercisePlanDetailState.finished);
|
||||
final String countSerie = widget.exercisePlanDetail.exercises == null ? "1" : (widget.exercisePlanDetail.exercises!.length).toString();
|
||||
final String serie = widget.exercisePlanDetail.exerciseType!.unitQuantityUnit == null ? "/1" : "/4";
|
||||
|
||||
setContext(context);
|
||||
return Container(
|
||||
color: Colors.transparent,
|
||||
|
@ -3,7 +3,7 @@ import 'package:aitrainer_app/util/common.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:liquid_progress_indicator/liquid_progress_indicator.dart';
|
||||
import 'package:aitrainer_app/library/liquid_progress_indicator/liquid_linear_progress_indicator.dart';
|
||||
|
||||
class AppBarProgress extends StatefulWidget implements PreferredSizeWidget {
|
||||
final int max;
|
||||
|
@ -258,10 +258,11 @@ class _BMIState extends State<BMI> with Trans {
|
||||
),
|
||||
),
|
||||
initialValue: widget.exerciseBloc.height.toStringAsFixed(0),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: false),
|
||||
textInputAction: TextInputAction.done,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||
onChanged: (value) => {widget.exerciseBloc.add(ExerciseNewHeightChange(value: double.parse(value)))}),
|
||||
onChanged: (value) =>
|
||||
{value = value.replaceFirst(",", "."), widget.exerciseBloc.add(ExerciseNewHeightChange(value: double.parse(value)))}),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
@ -294,11 +295,12 @@ class _BMIState extends State<BMI> with Trans {
|
||||
borderSide: BorderSide(color: Colors.white12, width: 0.4),
|
||||
),
|
||||
),
|
||||
initialValue: widget.exerciseBloc.weight.toStringAsFixed(0),
|
||||
initialValue: widget.exerciseBloc.weight.toStringAsFixed(1),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
textInputAction: TextInputAction.done,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||
onChanged: (value) => {widget.exerciseBloc.add(ExerciseNewWeightChange(value: double.parse(value)))},
|
||||
onChanged: (value) =>
|
||||
{value = value.replaceFirst(",", "."), widget.exerciseBloc.add(ExerciseNewWeightChange(value: double.parse(value)))},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
|
@ -3,7 +3,7 @@ import 'package:aitrainer_app/bloc/exercise_new/exercise_new_bloc.dart';
|
||||
import 'package:aitrainer_app/util/app_localization.dart';
|
||||
import 'package:aitrainer_app/model/fitness_state.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/library/dropdown_search.dart';
|
||||
import 'package:aitrainer_app/library/dropdown_search/dropdown_search.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
@ -213,10 +213,11 @@ class _BMRState extends State<BMR> with Trans {
|
||||
),
|
||||
),
|
||||
initialValue: widget.exerciseBloc.height.toStringAsFixed(0),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: false),
|
||||
textInputAction: TextInputAction.done,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||
onChanged: (value) => {widget.exerciseBloc.add(ExerciseNewHeightChange(value: double.parse(value)))}),
|
||||
onChanged: (value) =>
|
||||
{value = value.replaceFirst(",", "."), widget.exerciseBloc.add(ExerciseNewHeightChange(value: double.parse(value)))}),
|
||||
);
|
||||
} else {
|
||||
return Container();
|
||||
@ -361,11 +362,12 @@ class _BMRState extends State<BMR> with Trans {
|
||||
borderSide: BorderSide(color: Colors.white12, width: 0.4),
|
||||
),
|
||||
),
|
||||
initialValue: widget.exerciseBloc.weight.toStringAsFixed(0),
|
||||
initialValue: widget.exerciseBloc.weight.toStringAsFixed(1),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
textInputAction: TextInputAction.done,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||
onChanged: (value) => {widget.exerciseBloc.add(ExerciseNewWeightChange(value: double.parse(value)))},
|
||||
onChanged: (value) =>
|
||||
{value = value.replaceFirst(",", "."), widget.exerciseBloc.add(ExerciseNewWeightChange(value: double.parse(value)))},
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
|
@ -107,6 +107,7 @@ class _BottomBarMultipleExercisesState extends State<BottomBarMultipleExercises>
|
||||
}
|
||||
|
||||
List<Widget> getChildren(TestSetExecuteBloc bloc) {
|
||||
print("Isset? ${widget.isSet}");
|
||||
final List<Widget> list = [];
|
||||
if (!widget.isSet! && !bloc.hasBegun()) {
|
||||
list.add(GestureDetector(
|
||||
@ -174,7 +175,7 @@ class _BottomBarMultipleExercisesState extends State<BottomBarMultipleExercises>
|
||||
color: Colors.transparent,
|
||||
),
|
||||
Text(
|
||||
ret['message2'],
|
||||
t(ret['message2']),
|
||||
style: GoogleFonts.inter(color: Colors.grey[800]),
|
||||
),
|
||||
]))),
|
||||
|
@ -227,27 +227,6 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
||||
Divider(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
/* TextButton(
|
||||
onPressed: () {
|
||||
widget.onSubmit();
|
||||
/* showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return Victory(
|
||||
victory: true,
|
||||
);
|
||||
}); */
|
||||
},
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
|
||||
Text(
|
||||
t("Save"),
|
||||
style: TextStyle(fontSize: 16, color: Colors.white),
|
||||
),
|
||||
],
|
||||
)), */
|
||||
]),
|
||||
)));
|
||||
}
|
||||
@ -276,7 +255,10 @@ class _ExerciseSaveState extends State<ExerciseSave> with Trans {
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
textInputAction: TextInputAction.done,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 80, color: Colors.yellow[300]),
|
||||
onChanged: (value) => widget.onUnitQuantityChanged!(value)),
|
||||
onChanged: (value) => {
|
||||
value = value.replaceFirst(",", "."),
|
||||
widget.onUnitQuantityChanged!(value),
|
||||
}),
|
||||
]));
|
||||
}
|
||||
return row;
|
||||
|
@ -152,11 +152,11 @@ class _InputDialogState<Event> extends State<InputDialog<Event>> with Trans {
|
||||
borderSide: BorderSide(color: Colors.white12, width: 0.4),
|
||||
),
|
||||
),
|
||||
initialValue: widget.initialValue.toStringAsFixed(0),
|
||||
initialValue: widget.initialValue.toStringAsFixed(1),
|
||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||
textInputAction: TextInputAction.done,
|
||||
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.yellow[300]),
|
||||
onChanged: (value) => this.inputValue = double.parse(value),
|
||||
onChanged: (value) => {value = value.replaceFirst(",", "."), this.inputValue = double.parse(value)},
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
|
@ -279,7 +279,11 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
automaticallyImplyLeading: false,
|
||||
backgroundColor: Colors.transparent,
|
||||
title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: [
|
||||
SizedBox(
|
||||
!activeExercisePlan
|
||||
? SizedBox(
|
||||
width: 50,
|
||||
)
|
||||
: SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
GestureDetector(
|
||||
@ -318,18 +322,22 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
}
|
||||
},
|
||||
),
|
||||
activeExercisePlan
|
||||
Cache().activeExercisePlan != null
|
||||
? GestureDetector(
|
||||
onTap: () => showDialog(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return DialogCommon(
|
||||
title: t("You have an active Test Set!"),
|
||||
descriptions: t("Press OK to continue"),
|
||||
descriptions: Cache().activeExercisePlan!.name,
|
||||
description2: t("Press OK to continue"),
|
||||
text: "OK",
|
||||
onTap: () => {
|
||||
Navigator.of(context).pop(),
|
||||
if (Cache().activeExercisePlan != null)
|
||||
{
|
||||
Navigator.of(context).pushNamed("testSetExecute"),
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
Navigator.of(context).pop(),
|
||||
@ -348,6 +356,11 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
|
||||
);
|
||||
}))
|
||||
: Offstage(),
|
||||
activeExercisePlan
|
||||
? SizedBox(
|
||||
width: 10,
|
||||
)
|
||||
: Offstage(),
|
||||
]));
|
||||
return sliverAppBar;
|
||||
}
|
||||
|
@ -2,8 +2,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:aitrainer_app/model/workout_menu_tree.dart';
|
||||
import 'package:aitrainer_app/util/trans.dart';
|
||||
import 'package:aitrainer_app/library/dropdown_search.dart';
|
||||
//import 'package:aitrainer_app/library/dropdown_search.dart';
|
||||
import 'package:aitrainer_app/library/dropdown_search/dropdown_search.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
|
||||
|
@ -83,7 +83,12 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
.toDouble() -
|
||||
45,
|
||||
child: GestureDetector(
|
||||
onTap: () => onPressed(widget.exerciseBloc.customerRepository.getPropertyByName("Weight")!),
|
||||
onTap: () => {
|
||||
if (widget.exerciseBloc.customerRepository.getPropertyByName("Weight") != null)
|
||||
{
|
||||
onPressed(widget.exerciseBloc.customerRepository.getPropertyByName("Weight")!),
|
||||
}
|
||||
},
|
||||
child: Image.asset(
|
||||
"asset/image/merleg.png",
|
||||
height: 120,
|
||||
@ -181,7 +186,6 @@ class _SizeState extends State<SizeWidget> with Trans {
|
||||
}
|
||||
|
||||
void onPressed(Property element) {
|
||||
print(element.propertyName);
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => InputDialog(
|
||||
|
@ -630,13 +630,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.4.0"
|
||||
liquid_progress_indicator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: liquid_progress_indicator
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.3.2"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -846,7 +839,7 @@ packages:
|
||||
name: purchases_flutter
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.2.1"
|
||||
quiver:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
|
||||
# Read more about iOS versioning at
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
version: 1.1.10+65
|
||||
version: 1.1.13+66
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
@ -46,10 +46,8 @@ dependencies:
|
||||
flutter_html: ^2.0.0-nullsafety.0
|
||||
wakelock: ^ 0.4.0
|
||||
timeline_tile: ^2.0.0
|
||||
purchases_flutter: ^3.1.0
|
||||
purchases_flutter: ^3.2.1
|
||||
package_info: ^2.0.0
|
||||
liquid_progress_indicator: ^0.3.2
|
||||
#audioplayer: ^0.8.1
|
||||
ezanimation: ^0.5.0
|
||||
confetti: ^0.6.0-nullsafety
|
||||
crypto: ^3.0.0
|
||||
|
Loading…
Reference in New Issue
Block a user