From 4bd1950ffd8c75c3372483d9571b56f2fcc19655 Mon Sep 17 00:00:00 2001
From: bossanyit <tibor.bossanyi@aitrainer.app>
Date: Tue, 12 Jan 2021 16:45:43 +0100
Subject: [PATCH] WT1.1.4 build 45 android fb, iap

---
 android/app/build.gradle                    |   2 +
 android/app/src/main/AndroidManifest.xml    |   4 +-
 asset/data/promotion_codes-month.csv        | 200 ++++++++++++++++++
 asset/data/promotion_codes-yb.csv           | 101 +++++++++
 asset/data/promotion_codes_ya.csv           | 101 +++++++++
 i18n/en.json                                |   6 +-
 i18n/hu.json                                |   4 +-
 ios/Runner.xcodeproj/project.pbxproj        |   4 +
 ios/Runner/Runner.entitlements              |   2 +
 lib/bloc/sales/sales_bloc.dart              |  43 +++-
 lib/bloc/session/session_bloc.dart          |   1 -
 lib/model/cache.dart                        |   2 +-
 lib/model/product.dart                      |   1 +
 lib/repository/workout_tree_repository.dart |  39 +++-
 lib/service/exercise_tree_service.dart      |  19 ++
 lib/service/exercisetype_service.dart       |  22 ++
 lib/service/firebase_api.dart               |   6 +
 lib/util/platform_purchase.dart             |  72 ++++++-
 lib/view/sales_page.dart                    | 214 ++++++++++----------
 lib/widgets/app_bar.dart                    |   3 +
 lib/widgets/dialog_premium.dart             |   2 +-
 lib/widgets/home.dart                       |   8 +
 lib/widgets/image_button.dart               |  23 +--
 lib/widgets/menu_page_widget.dart           |  53 ++---
 pubspec.lock                                |  16 +-
 pubspec.yaml                                |   4 +-
 26 files changed, 772 insertions(+), 180 deletions(-)
 create mode 100644 asset/data/promotion_codes-month.csv
 create mode 100644 asset/data/promotion_codes-yb.csv
 create mode 100644 asset/data/promotion_codes_ya.csv

diff --git a/android/app/build.gradle b/android/app/build.gradle
index 35efa81..43a6c8c 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -78,5 +78,7 @@ dependencies {
     implementation 'com.google.firebase:firebase-analytics:18.0.0'
     implementation 'com.facebook.android:facebook-login:5.15.3'
     implementation 'com.android.support:multidex:1.0.3'
+    def billing_version = "3.0.0"
+    implementation "com.android.billingclient:billing:$billing_version"
 }
 sourceCompatibility = '1.8'
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 7f52f63..a80fc66 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -50,12 +50,12 @@
             android:value="2" />
 
         <meta-data android:name="com.facebook.sdk.ApplicationId"
-            android:value="@string/app_name"/>
+            android:value="@string/facebook_app_id"/>
 
         <activity android:name="com.facebook.FacebookActivity"
             android:configChanges=
                 "keyboard|keyboardHidden|screenLayout|screenSize|orientation"
-            android:label="WorkoutTest" />
+            android:label="@string/app_name" />
         <activity
             android:name="com.facebook.CustomTabActivity"
             android:exported="true">
diff --git a/asset/data/promotion_codes-month.csv b/asset/data/promotion_codes-month.csv
new file mode 100644
index 0000000..86abb63
--- /dev/null
+++ b/asset/data/promotion_codes-month.csv
@@ -0,0 +1,200 @@
+Promotion code
+ - A7DXXDNMKXU0KUJAEW70PRF
+2HLKJ93QP0TTGYFB4EL383L
+VDZBBGVMUUZ9PF2HTPG7PJ8
+V7RF0U3H6T0CY5LXX6AH7A4
+D63MQ1JPW6BQ4P0ZQM9UNQV
+ZDT7SSQB01FG4LCE67APADL
+U6953FSGRD54HYSAP27BQSA
+P0EHCGYHBM8PCVDY3AETGBY
+RUQX8TPKLT83WZ102EQ18B6
+LZ7MD5N30VQ6RD13J7NXHLL
+02FR52AH4WSANVMFGNQLBHX
+NLT4166PUJYW6ARAX76VK6Z
+TT6J3EBD56YZEK5T7R48ZB7
+PJ9APMP07V716P0MZQ1QQZ4
+1LAEA5MAVZCQ6Q6V746VWHA
+UR80FUSC88S4ZM6D7F2LAHX
+QGSTE9Z6T4ZTBR7D18ENZZE
+42F6RJ8UC0JGTJ3J3SPAW51
+Y1Z3S9D375EW5QG0KDWHRN5
+5KSKAP7JMSZB8KFWQCNJ2EP
+RFPKVGG2HUTLJDS293SK7T5
+6AH8L8V6ZDXRFDGWLD7XC1R
+L34MAXPGWBPHHEDRJ6J56Y2
+ZHD36F0FSPQ0302UG9JG4SJ
+A534UX0580PET9ZLRJGSJBN
+H8DZKTCYBXX3Y03UGQFVFFL
+2EN7JH4A3KCJB2H49WBT4NX
+XKP4HLPL738ZWAHH0DFPV73
+QA980ELAHDVJKAAALCSX3EC
+RRXA7TKYR8T0GRUS7QEBMU6
+3E9K4YZ4JG6UM9A03LQYX8Z
+YTYYQE4B1HNCAPVEWHAHBYN
+TAUZRSDGB8HT4JHWT04R0T0
+2APA0FT1DH0XM35PESM7YX0
+CVLTAJM0NF1GX46FEYCKXR1
+A8GH58V40TSC6L86ECWRNBT
+QJ37ENK3TK3FTZA250DGS02
+TJJWKUMBQRPTT8VWZDF4W9X
+CM6DDDUYVCGSGXZ36D5N6WW
+AZMUZ9EPL0JBHYKGRK3MCK0
+12MV9LC4BE4KGEDEW5X2MEM
+41F0GRVWJSLEAUAY0ALUN1V
+PPPHG266FFF6QBGJSL8WBDF
+MGP71PUFZ6NKLPP4VF8DS3T
+LXA6SH75WZ8KY4BEUV0S85U
+447FRJGYW2902PLLXZYTRAU
+D9EMMELU70PXZ8AKUZ56WCZ
+CZ4VPRSD6RFCGRDM1SVU2BH
+1ZTL14ZD7GHVB6B0NQMTCX5
+SA5W6ABBE74VUJV077C9A7E
+WB9EMATS4DHY3N2QL8WPXGB
+XQ368K414VJVVAS4G0EBT7C
+KGXV8WTQZ39WUUFYUJQXS1Y
+KW9920H2TDVJG9M6WVH2MBZ
+EZUSXBLAT69K7MBYUULPSUY
+3ZW2R3HFQB0GT27253L530Q
+WNWUYXYZZLVT5EK5NH4UMB7
+7WSV8KB1DH5XEBE9ZBTVSVF
+0Q3USEXJDRN219V66275B4H
+U6LKPXG16Z83A1RA320P0U6
+PAV3UQXD61NR528X1GND42R
+6NNZ9MVWZESFPHV0VBQBMNN
+BD2XLH4HKJWCGPY9C1AJGNW
+RQTLUQ1ZZJZBET76071WT89
+RBKQRGP9E6QGUX3KAJXF20K
+UGM5QUE0EXKEBE2A75ECNSM
+N2P0H1LFS2YEKX64D2PWDN7
+P6VJLEAKABRGFVR4T5DH1X5
+TJ815RNL5A460XJG4THR9JL
+YL0XY8R2TBTP5N5F9S3VWSV
+DU32C5H5U4GLT0509DS9G2K
+9DXV8W7QU9L63EY7XJVYTQ7
+UXNLD05CKKX20YKKNLVJ4BS
+VYDMRWTW5FJ76XGLSML71QU
+MBJJHEJPTRY2HQXLLPJ51XR
+XM63E19C75AJUBHH98D7W6C
+PTAU2W57H36U9U547UUND9G
+F1MZVKQ0Q4186X2JAPKW4RP
+MJRP26W2QM6XKUJDKFXX6AY
+AFN2GK30M9XNAPCF6GA1PZY
+GMYZDKLK428WS94GYHSW97U
+WVJHNTJE2USGWYAUB2G2ZNK
+DPYWSJETW05X990Z0U2MWBS
+S8U1061Q6LRZNGWHTGJ04U0
+HTLC06BVKKBKS7SBVK26J45
+A91PFKAHJMMXFTAHRUB9ENK
+KXPJ0AV2QURS3T9Z3HR0RN8
+V24WFCGMMQ1X38EUXXAVCGW
+263NEVRL247Q3D82PU5SFDK
+Z4QPPMN3J2T12VTGFVEZ2K7
+29F4W2RCAWRMK9P7KWRQ0WK
+LHJEC87AM9TRC0C0JX3XLGX
+PFSML2E11VJEB9GJ9SR1T36
+ZECQPLLUVX3QR61WMUX42HA
+K8MJAX3THB3FCWZT9VB2GSV
+HV4NHY2E3YJ836HH5KKU9Z1
+H6VN3YCXJYL5KR63QNGUX1C
+MDLNPC7H171QQN2C4SU0MZ7
+48HAF1RBHFWC2H8ZUHU8MGG
+48Z1MS05VFAB5ZKDEYB17TA
+V5LGP8113UJJ1SEWC5B5GTE
+RR5FP5CY1JB2WB9KY0YRKJR
+AYGQQN8FFPGY557PG6VGTTK
+PXT14ECUUR2MYP7XH9LYUQ6
+FED9VS405XMWYHW2P14NGJN
+V5NBC31P2B1A9D536ERVBYH
+AUHL02U2UDZY9N25Z0QE9C8
+JLSRMKPW82XY5EALCPT1P7G
+JM2BQUT9ZM3DNMDLVPATZGP
+C26KUVKFHL0VJ03H95G6F2Q
+LBLDHBEA63LH8S97SBLLA2C
+GYNB2CCAU6QLGW79N2UJ4UT
+1KPWT2JNULPBE3B9H8FC8NL
+EPDC7FRE705861ZMRJ71BV4
+9E0CDJTDCG5HD7C2LWPFDS7
+D72UZ0B4EUBZE8C9ZNX7XVP
+W2S98ZA8BW5NJ7RKHBSEE7P
+HMCV6KNUVY3Q4WGM3ZVRKNY
+U0BQEC40RZ5CDLQH26PP4YT
+MTLLSJJN4LQVRS7JFL2Y2K6
+Z0G8BJ8NS9U8HYBHN3N99AE
+9J14SSRZAMZ31DG1ZXNVNNV
+WPS91QFT25LT7YXVYPG75BP
+G3A4HNEVT5CH077FWZZUK88
+QDKUWSRJR5K6Z97C4ZUGTWH
+5YZTDJ1J85QXZH6TXX3TDDQ
+ZM500MPBGWU0F2VHQQUKZ5T
+TTF0R47WTKWPJT4LATUKWHQ
+JS5A5F0RCZRVB971F2LE2HS
+1D8A1XVA3SKFCFWRSXQYRFV
+K3LE2X4GAL1MYPR9RY9EN6G
+24X5VZDJD3YZUABYW6YSVSC
+9C3R9XDFL24D7CTZMFH2CMN
+VX4B1HLX8VFZS2MPNN094TZ
+4Z7EKRK9YC3T130V0QWMKWL
+8AXQF15N9VESKNQRVXMGG87
+79T0R5HWKK91LUKJ0PMNDCB
+YG5ZGFAAWC9ZD8SM1HARLBL
+BMD30152E4L9WUL0Q5V7AF3
+R40VFDKQH0SVB3DJK170ZAZ
+D74L2A1KJED72TZ3DWVH8ZP
+0WT613SN6Y4K3J2G77D0EUT
+W7EH5EV6KZ5T8TA0DRSYCED
+U8HDE2HVB09ZB9TN4KAEAPR
+JV75U798X715X36PN2PE0D3
+UUD5YAN2J2UXG15LBHHCP7G
+W1W9C458C72XM1ULP1BVXPR
+LR0UF5R33VN4DZPJUGQA0CY
+A9WFKNJAW5K0D1SJNVY2DAW
+UZ8TNXA91J8GASZEG3GXZQM
+05DZ47KFJKPW6FRTJB1408J
+37XQMR4EJ7RLDDDD3PZWWXY
+NVGJTTW0GZCYKC07BDVQHVR
+7MK2P0CJRR4DNVLY0K564T4
+L4S2NBED58K86MK7C9Y42ZT
+LMB4TR1HPB3C6F6HDWKJ4A2
+NRTFR3Q4K4EDHH8WM2ADAKA
+QLPLCN13Z2HC8ELBJ2HWZWR
+KCWQE1KNVC3KW7XZGRVAU5Q
+69GSLNNEC0N3FU4CA09EEGE
+LQLPJR7VXCNGQZHZXM3Q09E
+ZABXFHVGNKMBSF1KZD1JYGD
+MH29T4T2BQW3BCU6BEZVNWB
+SG0FS4R1W2TSG6V7ZU00UVD
+5R99FUV2X6DU0QQFMACMV37
+AMPHQR8S0Q5D85XFZXS9WM8
+AU1325QFCDMD92BVJ1UNKUB
+R9X4QMJ11NA9THEXPSCFCES
+5MPD73H81E0ND5PAF9QTTA1
+R7UGAY5BBNP7PFBUK9F0UB2
+PLRAMYCRMTM8ENT7LDXZG4R
+U4MJ3WGBZ4P04G14C0VPF1T
+CFNQEFSUEKN1FLN9LMF5T7W
+JBNZREJAFVY82LMU09H59NH
+FH641QN4A5R139B1XDVR95H
+71WJ7TL1SGBR1X4HK01RB3A
+53SQJPFBWWM2QPHD7B5Y1D9
+HP56RB9QH0N0KFQDXDFJN4J
+YFNL1WXSLQLBGY8H6H7SQKZ
+N0K4B0CRE8XGFQ6R2J258XE
+6E4MMLDN7PKYKVBC5HY84UB
+LH4B02LJE3V4QWNBC92P36T
+46K1R5XQJ8DNFL2S9PSVE05
+KTNP7KXY8P3BH4GJCBCHAW6
+WFEX4UK60WTQDJSNQ2BSJRM
+LMVKNTH5SVTV4B6LNNZW3H8
+CWGQBAF6AZ82NU8U47MKE7Q
+WNYXQQX0WEEVQTF8JH690S1
+5WJA3TF43HKWSBUUNB9F1A5
+CL78PV3T9JTFDNF1Y9CA9YS
+NZPF8XE8562BCPQ3E4BLMCT
+HHZBNN0US3LG1MUR6A7U1L4
+40ZS9086PMMYHEZZCMD8E19
+LJZXQ3JX5LNSBLDA3B2HAZZ
+2KG86G8HC09KQ6AG3NP658C
+KEW6N6ANMUABGEP6YPEAHH2
+V2TGMTNW2PKSSCR9J7V0GU8
+X40UEV1PEN3FJY7WXVS3M57
+QXYMX3Q8J48KN0SSMKK6F7V
diff --git a/asset/data/promotion_codes-yb.csv b/asset/data/promotion_codes-yb.csv
new file mode 100644
index 0000000..02dd2e8
--- /dev/null
+++ b/asset/data/promotion_codes-yb.csv
@@ -0,0 +1,101 @@
+Promotion code
+-- KJM6GH5NTDDW12VDWK3D7AU
+-- 0CZG2AWS41G29VD2S1C3FBQ
+9H499GCQKXKEPMWTE6NYJ4L
+09KHJXX8Y4AE3A4DPZSCZB0
+HT7GJR81R2Q5XWGD81E0ZY1
+ZJNPW2ACQQQVJDPDNG1JYYR
+Q8BTA7DTADKF0S7YR8F6EKM
+ECZRD2BU74JL3T94ZD04C4Z
+NMLGBZP92MN9VH15FH4PJJK
+PSUPGVX1BFPDAM5BPCS3FQQ
+40PJBGMGJR0UHLEWBNWF32U
+W7N5D66YFKNNRXE6CJNXDT7
+A1Y1V52C3WLUXFFL4F42LVZ
+FM7EZK3HH6TN5YE702Z9AM5
+D5YSSBDF982P88YBGUNLFWF
+JCY6JHSXGP3XVT471GS32TB
+RMAH0VTA38WGR0YECTE6H09
+DTLSFDX7ZAA4HPEJJCKEZF5
+P8ZR8821XMNTMFN66DYG825
+THHUYPZ17EV00G2NM84EJWR
+E7ZHT83XN6KCXPQ3KRXCL0D
+R8BDSFN2F4GLNZU2V5QMSFF
+7VWXPULDVL9LGM7TZRKCBQP
+BD4UA5YKAV29CA8GN014RDQ
+4W8GX1EKCVEH17SYZ9MFX85
+SZ8DL9G6SCMCHMS7JA7HCDT
+D383P1Y0RCN5M49G454XJ4G
+7DC9FKU6PLYL7ARNL9FUMBX
+80RFXJF8ZHC6S4X592BTDR1
+VXJ9T0CGE2RLPSCRHGVDLK8
+W7LGSSRMEGGLDDT568WBMUT
+Q5RG5QTLG0N285KAD43QGNN
+QUYKWTNZ9MBQ1EL49WS2FB6
+GEQSQ8W0SHDK52RJTHBS45E
+DZNBW0L2M6MF8JCKVT15SM9
+KHL0A6MKBY4WF4KGYVSEXU9
+HWEVEH5QS74RD06XGSXUP4R
+CF1HCXMYWNT0GEK757DR7QJ
+38NSEXPC1XG573M6FVPU1DS
+RZ1QJ6TA68N0SPUT0FM6TYR
+SRHCQJ4ANJKLHH9WV127VTU
+RYD0XV94L770S9W1RW22AZY
+EM6TWEC71ATHZRU159H577W
+BZPJDHBUA0F37ULKUYKX3MD
+SL5PSDXWFKMWRSB1VTVK982
+H630F22CDLKGTE7128ZSR7V
+FXP9FC311KSFDX87KA7NDNS
+4ZQX57DTQ82T7B2A113RRA2
+GF0X3UK29CRPFUSMTKJY7VJ
+AHSZLDVUCDMXXC840DDERCX
+T9C5PVP0AMS48UW88L9Q1BQ
+G6SKQQK9EAVJF1TM4J2SK4H
+3Y00PYF2QKRQN4ZNZVWERGH
+QCSEMNG7G0704UHE93KENLH
+MUB9P4Y1F5VLPTSGRT6E1ED
+KE9EC1JH63LBX79BHX1WQFH
+PD16F8BZZRC94TFJRQ3L3PG
+ANQDQ2KJTVQQTYXPAUELB1S
+RAXT8YFK3LAALY0HLWX9KAQ
+4CR33PYZZ7RGKWDTCFD9XVK
+NWV7CJX6AG78NR7769D190Y
+EC490NHL19NZV0GF76TLQXQ
+9E42VMUFB13NU6N8QGL2TYT
+ED99UQ1VFVJSHPGXC8ERAEA
+XZU9XZK7RKL8GRTFS5LUDXD
+677FF9GZVHEYWC13N5HGSGD
+NJVAWAYGEZAL6JCVB0D43CD
+CJ4JGJZQW5JVLN5BDGKGLT6
+VHB93V8U4ASWS78ZUYZCN19
+3JGM2U3EPZ8MW4TBZW7H53G
+2FYZ7G4JRWEMZMDPQQSJUTV
+5E3C44SU9R3YLBJDGR3GQM8
+S1X2HWGFDDL61A48EY777DU
+5MHRAX98UTQQ372ANJ3WJB0
+X5C7UB37VQ3R4PFT38FDAA5
+PFG41S3LRSXPQ9ZFMKFTGDQ
+TRXZU2HEVR1TPXXQEGNU611
+0C4ZVMKCHVJVKASB78X6CYL
+ZVHV1LA2JZXD90CEP375W8R
+R9TGDA50REYPP4FKCF9GK6H
+DGDYA7XVR0SLX6CWWMSVVDB
+65XLN0P4LBQ6J81VJ1JD0CH
+RYV7SZLD8B6N92QA8V4PT5N
+RDK07CND4QR8QRCWNZMEMJA
+NKNJ09BPS7M4E4CJ4H3WUX7
+554X7A7Z0F4MPS8NX8H5GLG
+5XQZ5L9Y8BTB2C4DRQKDW53
+9T9KK0DUQQL7Z3H19HCFM4C
+ZBF62Y2PF1M5T2B69PEKECR
+DVG93BR8BVT0DW3V10USX3H
+4DUQ0CAMF0S08YBVWTG4Z6Y
+0EC19Q18NTVE1S8NN7EWFSQ
+L9617J33F5GU2LRK4HQ0AY3
+D8MHJSK6E86QCLFYFBMJ63K
+AJ8ZQK2SYGK6YK4ZWAJPV5H
+WL7NJ28NRYQ4J36F13HX65W
+VP5MTQZB78ZGJ5SKUQYJ67Y
+6DL9WDQ3U1A8A9Z30B05KZL
+VXF8A7QMEQCLQAY9P7B5EZA
+KCNPFPUHRFXPZWCACFQ8YW6
diff --git a/asset/data/promotion_codes_ya.csv b/asset/data/promotion_codes_ya.csv
new file mode 100644
index 0000000..710c3fd
--- /dev/null
+++ b/asset/data/promotion_codes_ya.csv
@@ -0,0 +1,101 @@
+Promotion code
+DULPYTPABG7Y51GYL6A8Z72
+8A8PH0M87ESVL2YTMXXFVKJ
+8X2976ZLFR61SP85NGVK0AA
+8CDC60CU9HLBNJEQ9F2QPC7
+VSHTMHLJTBAV731JX52MNQ4
+C302XQN62ZU8F27BQ1RBGT9
+6FDAGQVCGZQSCA56XXA08DM
+KK0KBEUGWW3521NA31GV3T4
+PAT2TF5A44RAMD883ECHYCG
+CGRHCDVKA9Z8D7RXV97BRPY
+E1FQ4V968KYEU6JDQ8TQEAT
+NEH6BUEAT9UCHAX1QJD0CJJ
+QHLBD3GN473MHT30QAAD0U8
+2XK0LYH77U6EUQ3NM8M2U1C
+CG6C3H6BK4RZAFS9WF46YU0
+BY6Y07P0AYT5TH2VQ8X267N
+9C5VW5X5DHHKJ8Q40ZM81EG
+P5Y8K895CP4AVBYVDCG5D60
+T5S0M4LN7SAX27B4RKDGKQ3
+6G34MCK50FNLZ8ZUTWLF5AJ
+JZD22RSD7WRKXLP8EDBWH4U
+7V4WT93MFY03AB76NJH8SXJ
+CY4VKZ74MYUEM3KTGL0LHLT
+XP4U1930D44QAUUEM16PLCT
+U5M7FPV2MHUA6VEJN2XWVKY
+D6EC4QWWXDYUULAW8QT8AHF
+LJ4NJAY7KCM25WT0A25BPN6
+K6SQLF2C9APJBZF04BRDNH2
+1C8L76C512HBULG3NQUA84K
+H1VR3131G5G2ARSLGVMM4GF
+7AHJ0EB97PA4XY1GLTVTTHN
+AUWZGVK4ULY52210Y8ULD30
+D0JY0HW6MLHAPCKBQTMVFQ3
+TSE722BT94HNSY3GRV28UN1
+H8Q1EAYYS5JDX2KU4J3P344
+U3K5S83M1ULR0ETL8XFJ8VJ
+XEG86F51SXXY5P2HZG49H58
+8HFS2KE099XZMHYEDEQN84Z
+3GUH12E4V5RYV9J8ZMBETZ8
+DHKTFWBNJ7R1CXV2E41K3CK
+49KK8J5Y1K2LPERB6G09P9M
+VXYYBTMLPXAY4EGUENVLAZR
+5AHZGKA02K4717MD2A94EPJ
+7DGNRVD16Q2GP5N9XL3Y0EG
+7LG8U55NRA6TKRT3VPY1RME
+S8RY3KSDJPMW0Y26VEC4RVG
+WS043ADBZ4HHZ57U9SZRXUP
+K7YET0Q249XNFH7NX8GX575
+UEJCE8CMDSUKJNBTVN9NUBA
+UDQA1SY0L9FRHZBKR8GHWEN
+XM4K7S04G018P3NQHS8TV2Y
+9LJT7CSYTMJALZ6L7TUGP3R
+SRN1UNBW6BSAYUFFJ7MQ690
+7XHX75BCBMK5R1WKHDFJX2P
+RULRS8H8LKFZY8VVMRRD8DM
+N1Y3DSPBCC6CZTKP5NUMZ1D
+H4RAWV8Z8ZCS80QQMQ39AN9
+URF18Q5GTQ0A5WJG0MUCJ5G
+QPBHN1B2JNQB2THW2NWDMS5
+C6N0Z1D7SA7H9HLABSA2W5Q
+31CQANBKBPPUZ8FLHCYJ2WB
+GHGJV049LN066UYM239K4SV
+4NDWC74YQJKFJZHSHP6N4YG
+904EM94E8VEFLWWLT10W7C8
+HRLLGB3QHCW8PG75XWL9CV8
+SHEYF4F7B5F6LGLWGXYMBKV
+WABU07E42Z3FK2V06XLDQDC
+40KX6L2T1R839HWQHF8UWWU
+Q8XAXGQEZ2V847WMYKCV91A
+LK1MV8G85EV51XA43HVW5AA
+U5HB1KMVS1AUD21YE4ZXDS5
+5Y5SKU4MP2QGTUPKG3LEL8K
+FC8VS4S0SZ1VJUH4SNDKAQ4
+WUS35TBS78VWS4SSJQPG502
+2FZQLEF358H0LA2HGQAB57W
+KQVC3CHDNPDR1ADVDNAZDCH
+0AFT33YM8X7RTXT07KVVN21
+GP2M6QAM3G18MBC2ZYD73RL
+GFKSN039H70CYT70JM81SKQ
+2ECADR3TXBJ2CUWF6WKDF7L
+U2V944D5TB4TZXG6JCD003P
+PHG6QP4YT5TJZ75F58QADQ8
+GUVJVYANS8HPWQHMTNGHXGA
+USAL3QBLYWPCC0JXDQGK263
+V5M18UT9L2Q3EZ095TUAPQX
+W3UCUV9WW5HEG4UBX1M0U58
+YBSM2K271EJHJ23CSD6HS04
+HT8RFH4TMX9LJVA3FJDNRCG
+9HDPRJHG15E5275PDKXAFB7
+R95YEGEU7U8DR6DQUYMBKTH
+3LCXQ54B24GH4K5WU6G3DU9
+NHHTHNT2C42CARLX2RLFMUS
+WB5EW890X513DLFEW0QZX5M
+WDB6FSAFZ8JXLPKUF2JLWRB
+346AWN92NCYTK12NNV1SYMK
+V0TQG3F0XYBDPU946C13LMQ
+SA4HAPXW1TPVAFCG5P9H6Q3
+SMJJE6RY9W6Q6HWHEL7YSHU
+AHA16TP02C6NS83A8DSA9B2
+NSJVXY2H026YQB3ZJMZLY2E
diff --git a/i18n/en.json b/i18n/en.json
index 48fd81d..c324114 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -9,7 +9,7 @@
   "Logout": "Logout",
   "Tests": "Tests",
   "Change Language": "Change Language",
-  "Password too short": "Password too short (at least 6 characters)",
+  "Password too short": "Password too short (at least 9 characters)",
   "Please type an email address": "Please type an email address",
   "Exception: Please accept our data policy":"Please accept our data policy",
   "Please accept our data protection policy. For more information please click on 'Privacy'":"Please accept our data protection policy. For more information please click on 'Privacy'",
@@ -27,6 +27,8 @@
   "Please log in": "Please log in",
   "Exception: Customer does not exist or the password is wrong": "The email does not exist or the password is wrong",
   "Exception: Customer exists": "The email address has been registered already",
+  "Exception: Please type an email address": "Please type an email address",
+  "Exception: Password too short": "Password too short (at least 9 characters)",
   "There is an error: during registration:": "There is an error: during registration:",
   "Please select an exercise": "Please select an exercise",
   "Cardio": "Cardio",
@@ -162,7 +164,7 @@
   "Edit My Custom Plan": "Edit My Custom Plan",
   "Suggested Training Plan": "Suggested Training Plan",
   "My Special Plan": "My Special Plan",
-  "Star's Exercise Plan":"Star's Exercise Plan",
+  "Star's Exercise Plan":"Celeb Exercise Plan",
   "My Trainee's Plan": "My Trainee's Plan",
   "Execute My Trainee's Training Plan": "Execute My Trainee's Training Plan",
 
diff --git a/i18n/hu.json b/i18n/hu.json
index 79963ee..8c82843 100644
--- a/i18n/hu.json
+++ b/i18n/hu.json
@@ -9,7 +9,7 @@
   "Login": "Bejelentkezés",
   "Logout": "Kijelentkezés",
   "Change Language": "Nyelv",
-  "Password too short": "A jelszó min. 6 karakterből álljon",
+  "Password too short": "A jelszó min. 9 karakterből álljon",
   "Please type an email address": "Kérlek írj be egy email címet",
   "SignUp": "Regisztráció",
   "Exception: Please accept our data policy":"Kérlek fogadd el az adatvédelmi szabályzatunkat",
@@ -29,6 +29,8 @@
   "Customer does not exist or the password is wrong": "A felhasználó nem létezik vagy a jelszó rossz.",
   "The email does not exist or the password is wrong": "A felhasználó nem létezik vagy a jelszó rossz.",
   "Exception: Facebook login was not successful": "Facebook bejelentkezés sikertelen",
+  "Exception: Please type an email address": "Kérlek írj be egy email címet",
+  "Exception: Password too short": "A jelszó min. 9 karakterből álljon",
   "Exception: You have a previous Facebook login operation in progress":"Az előző bejelentkezés még folyamatban van.",
   "Exception: Facebook login cancelled":"Facebook bejelentkezés megszakítva ",
   "Exception: Facebook login failed":"Facebook bejelentkezés sikertelen",
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index cdc9f4f..b27c0d8 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -15,6 +15,7 @@
 		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
 		BB69292B2521AF45001FBA4C /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BB69292A2521AF45001FBA4C /* Launch Screen.storyboard */; };
 		BB81345024BB4BE10078D9A4 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB81344F24BB4BE10078D9A4 /* GoogleService-Info.plist */; };
+		BB8D3BFA25A8CBFE00BF29FE /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXCopyFilesBuildPhase section */
@@ -48,6 +49,7 @@
 		BB43773E2540715900D74BFA /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
 		BB69292A2521AF45001FBA4C /* Launch Screen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = "Launch Screen.storyboard"; sourceTree = "<group>"; };
 		BB81344F24BB4BE10078D9A4 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
+		BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = System/Library/Frameworks/AuthenticationServices.framework; sourceTree = SDKROOT; };
 		D5EDDC52125075FB9E21AD35 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
 		F39E6E227EB942E5663A6086 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
@@ -57,6 +59,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				BB8D3BFA25A8CBFE00BF29FE /* AuthenticationServices.framework in Frameworks */,
 				42B6B159AF35AFB6DE777DFB /* Pods_Runner.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -77,6 +80,7 @@
 		3ADC50290ED054951FAC1F56 /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				BB8D3BF925A8CBFE00BF29FE /* AuthenticationServices.framework */,
 				09BD889296C5C90D989820C8 /* Pods_Runner.framework */,
 			);
 			name = Frameworks;
diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements
index 903def2..f166400 100644
--- a/ios/Runner/Runner.entitlements
+++ b/ios/Runner/Runner.entitlements
@@ -4,5 +4,7 @@
 <dict>
 	<key>aps-environment</key>
 	<string>development</string>
+	<key>com.apple.developer.authentication-services.autofill-credential-provider</key>
+	<true/>
 </dict>
 </plist>
diff --git a/lib/bloc/sales/sales_bloc.dart b/lib/bloc/sales/sales_bloc.dart
index 8e26f1d..b37c91a 100644
--- a/lib/bloc/sales/sales_bloc.dart
+++ b/lib/bloc/sales/sales_bloc.dart
@@ -1,4 +1,5 @@
 import 'dart:async';
+import 'dart:io';
 import 'dart:math';
 
 import 'package:aitrainer_app/model/cache.dart';
@@ -6,6 +7,7 @@ import 'package:aitrainer_app/model/product.dart';
 import 'package:aitrainer_app/model/product_test.dart';
 import 'package:aitrainer_app/service/logging.dart';
 import 'package:aitrainer_app/service/product_test_service.dart';
+import 'package:aitrainer_app/util/platform_purchase.dart';
 import 'package:bloc/bloc.dart';
 import 'package:equatable/equatable.dart';
 import 'package:flurry/flurry.dart';
@@ -26,20 +28,46 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
     try {
       if (event is SalesLoad) {
         yield SalesLoading();
-        Flurry.logEvent("SalesPageOpen");
+        //Flurry.logEvent("SalesPageOpen");
+        await PlatformPurchaseApi().initPurchasePlatformState();
         this.getProductSet();
         yield SalesReady();
       } else if (event is SalesPurchase) {
         final int productId = event.productId;
         trace("Requesting purchase for" + productId.toString());
-        Flurry.logEvent("PurchaseRequest");
-        //PlatformPurchaseApi().requestPurchase(null);
+        //Flurry.logEvent("PurchaseRequest");
+        PlatformPurchaseApi().purchase(getSelectedProduct(productId));
       }
     } on Exception catch (ex) {
       yield SalesError(message: ex.toString());
     }
   }
 
+  Product getSelectedProduct(int productId) {
+    Product prod;
+    for (var product in this.product2Display) {
+      if (product.productId == productId) {
+        prod = product;
+      }
+    }
+    return prod;
+  }
+
+  String getLocalizedPrice(String productId) {
+    String price = "";
+    for (var product in PlatformPurchaseApi().getIAPItems()) {
+      if (Platform.isAndroid) {
+        print("PlatformProduct " + product.toString());
+        if (productId == product.productId) {
+          price = product.localizedPrice;
+          break;
+        }
+      }
+    }
+
+    return price;
+  }
+
   void getProductSet() {
     int productId = 0;
     this.tests = Cache().productTests;
@@ -51,7 +79,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
       trace("Previous ProductTest: " + tests[0].toJson().toString());
       productId = tests[0].productId;
       for (var elem in Cache().products) {
-        Product product = elem as Product;
+        final Product product = elem as Product;
         if (product.productId == productId) {
           productSet = product.productSet;
           break;
@@ -63,8 +91,11 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
     trace("ProductSet: " + productSet.toString());
     for (var elem in Cache().products) {
       Product product = elem as Product;
+
       if (product.productSet == productSet) {
         productId = product.productId;
+        final String platformProductId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos;
+        product.localizedPrice = getLocalizedPrice(platformProductId);
         product2Display.add(product);
       }
     }
@@ -76,7 +107,7 @@ class SalesBloc extends Bloc<SalesEvent, SalesState> with Logging {
     productTest.productId = productId;
     productTest.customerId = Cache().userLoggedIn.customerId;
     productTest.dateView = DateTime.now();
-    ProductTestApi().saveProductTest(productTest);
-    Cache().productTests.add(productTest);
+    //ProductTestApi().saveProductTest(productTest);
+    //Cache().productTests.add(productTest);
   }
 }
diff --git a/lib/bloc/session/session_bloc.dart b/lib/bloc/session/session_bloc.dart
index 281a1be..5f866bf 100644
--- a/lib/bloc/session/session_bloc.dart
+++ b/lib/bloc/session/session_bloc.dart
@@ -28,7 +28,6 @@ class SessionBloc extends Bloc<SessionEvent, SessionState> with Logging {
         // ignore: close_sinks
         SettingsBloc settingsBloc = event.settingsBloc;
         await session.fetchSessionAndNavigate();
-        await PlatformPurchaseApi().initPurchasePlatformState();
         String lang = AppLanguage().appLocal.languageCode;
         log("Change lang to $lang");
         settingsBloc.add(SettingsChangeLanguage(language: lang));
diff --git a/lib/model/cache.dart b/lib/model/cache.dart
index f81821f..7f68fac 100644
--- a/lib/model/cache.dart
+++ b/lib/model/cache.dart
@@ -105,7 +105,7 @@ class Cache with Logging {
   LinkedHashMap<String, int> _badges = LinkedHashMap();
 
   List deviceLanguages;
-  String startPage;
+  String startPage = "home";
   String testEnvironment;
   bool liveServer = true;
   bool hasHardware = false;
diff --git a/lib/model/product.dart b/lib/model/product.dart
index ab29866..5acba9a 100644
--- a/lib/model/product.dart
+++ b/lib/model/product.dart
@@ -12,6 +12,7 @@ class Product {
   String productIdAndroid;
   double priceIos;
   double priceAndroid;
+  String localizedPrice;
 
   Product.fromJson(Map json) {
     this.productId = json['productId'];
diff --git a/lib/repository/workout_tree_repository.dart b/lib/repository/workout_tree_repository.dart
index 314ac6c..28c2e0a 100644
--- a/lib/repository/workout_tree_repository.dart
+++ b/lib/repository/workout_tree_repository.dart
@@ -10,6 +10,7 @@ import 'package:aitrainer_app/service/exercise_tree_service.dart';
 import 'package:aitrainer_app/service/exercisetype_service.dart';
 import 'package:aitrainer_app/service/logging.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 
 class Antagonist {
   static String chest = "Chest";
@@ -47,6 +48,19 @@ class WorkoutTreeRepository with Logging {
     Antagonist.calf: Antagonist.calfNr
   };
 
+  Future<String> _buildImage(String imageUrl) async {
+    String assetImage = 'asset/menu/' + imageUrl.substring(7);
+    //print("Loading image " + assetImage);
+    return rootBundle.load(assetImage).then((value) {
+      return assetImage;
+    }).catchError((_) {
+      String imagePath = assetImage.substring(10);
+      String url = Cache.mediaUrl + 'images' + imagePath;
+      //print("Exception: " + assetImage + " will be loaded from the network " + url);
+      return url;
+    });
+  }
+
   Future<void> createTree() async {
     isEnglish = AppLanguage().appLocal == Locale('en');
     log("** Start creating tree on lang: " + AppLanguage().appLocal.languageCode);
@@ -65,7 +79,7 @@ class WorkoutTreeRepository with Logging {
       //log(" -- TreeItem " + treeItem.toJson().toString() + " active " + treeItem.active.toString());
       if (treeItem.active == true) {
         String treeName = isEnglish ? treeItem.name : treeItem.nameTranslation;
-        String assetImage = 'asset/menu/' + treeItem.imageUrl.substring(7);
+        //String assetImage = await _buildImage(treeItem.imageUrl);
 
         bool is1RM = treeItem.name == 'One Rep Max' ? true : false;
         if (is1RM == false && treeItem.parentId != 0) {
@@ -86,7 +100,7 @@ class WorkoutTreeRepository with Logging {
           treeItem.treeId,
           treeItem.parentId,
           treeName,
-          assetImage,
+          treeItem.imageUrl,
           Colors.white,
           30,
           false,
@@ -104,11 +118,11 @@ class WorkoutTreeRepository with Logging {
       }
     });
 
-    exerciseTypes.forEach((exerciseType) {
+    exerciseTypes.forEach((exerciseType) async {
       if (!(exerciseType.imageUrl.isEmpty || exerciseType.name.isEmpty || exerciseType.nameTranslation.isEmpty) &&
           exerciseType.active == true) {
         String exerciseTypeName = isEnglish ? exerciseType.name : exerciseType.nameTranslation;
-        String assetImage = 'asset/menu/' + exerciseType.imageUrl.substring(7);
+        //String assetImage = await _buildImage(exerciseType.imageUrl); //'asset/menu/' + exerciseType.imageUrl.substring(7);
         if (exerciseType.parents.isNotEmpty) {
           exerciseType.parents.forEach((parentId) {
             bool is1RM = this.isParent1RM(parentId);
@@ -117,8 +131,21 @@ class WorkoutTreeRepository with Logging {
             if (isEndurance) exerciseType.setAbility(ExerciseAbility.endurance);
             bool isRunning = this.isParentRunning(parentId);
             if (isRunning) exerciseType.setAbility(ExerciseAbility.running);
-            WorkoutMenuTree menuItem = WorkoutMenuTree(exerciseType.exerciseTypeId, parentId, exerciseTypeName, assetImage, Colors.white,
-                24, true, exerciseType.exerciseTypeId, exerciseType, exerciseType.base, is1RM, isEndurance, isRunning, exerciseType.name);
+            WorkoutMenuTree menuItem = WorkoutMenuTree(
+                exerciseType.exerciseTypeId,
+                parentId,
+                exerciseTypeName,
+                exerciseType.imageUrl,
+                Colors.white,
+                24,
+                true,
+                exerciseType.exerciseTypeId,
+                exerciseType,
+                exerciseType.base,
+                is1RM,
+                isEndurance,
+                isRunning,
+                exerciseType.name);
             this.tree[exerciseType.name] = menuItem;
             //log("WorkoutMenuTree item " + menuItem.toJson().toString());
             /* log("ExerciseType in Menu item " +
diff --git a/lib/service/exercise_tree_service.dart b/lib/service/exercise_tree_service.dart
index 1b83ead..7bbf7eb 100644
--- a/lib/service/exercise_tree_service.dart
+++ b/lib/service/exercise_tree_service.dart
@@ -3,6 +3,7 @@ import 'dart:convert';
 import 'package:aitrainer_app/model/cache.dart';
 import 'package:aitrainer_app/model/exercise_tree.dart';
 import 'package:aitrainer_app/model/exercise_tree_parents.dart';
+import 'package:flutter/services.dart';
 import 'api.dart';
 
 class ExerciseTreeApi {
@@ -15,10 +16,28 @@ class ExerciseTreeApi {
 
     exerciseTree = await getExerciseTreeParents(exerciseTree);
 
+    if (exerciseTree != null) {
+      exerciseTree.forEach((element) async {
+        element.imageUrl = await _buildImage(element.imageUrl);
+      });
+    }
     Cache().setExerciseTree(exerciseTree);
     return exerciseTree;
   }
 
+  Future<String> _buildImage(String imageUrl) async {
+    String assetImage = 'asset/menu/' + imageUrl.substring(7);
+    //print("Loading image " + assetImage);
+    return rootBundle.load(assetImage).then((value) {
+      return assetImage;
+    }).catchError((_) {
+      String imagePath = assetImage.substring(10);
+      String url = Cache.mediaUrl + 'images' + imagePath;
+      //print("Exception: " + assetImage + " will be loaded from the network " + url);
+      return url;
+    });
+  }
+
   Future<List<ExerciseTree>> getExerciseTreeParents(List<ExerciseTree> exerciseTree) async {
     List<ExerciseTree> copyList = this._copyList(exerciseTree);
 
diff --git a/lib/service/exercisetype_service.dart b/lib/service/exercisetype_service.dart
index 6afe41b..3d72e18 100644
--- a/lib/service/exercisetype_service.dart
+++ b/lib/service/exercisetype_service.dart
@@ -3,6 +3,7 @@ import 'package:aitrainer_app/model/cache.dart';
 import 'package:aitrainer_app/model/exercise_type.dart';
 import 'package:aitrainer_app/service/api.dart';
 import 'package:aitrainer_app/service/logging.dart';
+import 'package:flutter/services.dart';
 
 class ExerciseTypeApi with Logging {
   final APIClient _client = new APIClient();
@@ -11,10 +12,31 @@ class ExerciseTypeApi with Logging {
     final body = await _client.get("exercise_type", "");
     final Iterable json = jsonDecode(body);
     final List<ExerciseType> exerciseTypes = json.map((exerciseType) => ExerciseType.fromJson(exerciseType)).toList();
+    if (exerciseTypes != null) {
+      exerciseTypes.forEach((element) async {
+        element.imageUrl = await _buildImage(element.imageUrl);
+      });
+    }
     Cache().setExerciseTypes(exerciseTypes);
     return exerciseTypes;
   }
 
+  Future<String> _buildImage(String imageUrl) async {
+    if (imageUrl.length > 8) {
+      String assetImage = 'asset/menu/' + imageUrl.substring(7);
+      return rootBundle.load(assetImage).then((value) {
+        return assetImage;
+      }).catchError((_) {
+        String imagePath = assetImage.substring(10);
+        String url = Cache.mediaUrl + 'images' + imagePath;
+        //print("Exception: " + assetImage + " will be loaded from the network " + url);
+        return url;
+      });
+    } else {
+      return imageUrl;
+    }
+  }
+
   Future<void> saveExerciseType(ExerciseType exerciseType) async {
     String body = JsonEncoder().convert(exerciseType.toJson());
     log(" ===== saving exerciseType id: " + exerciseType.exerciseTypeId.toString() + ":" + body);
diff --git a/lib/service/firebase_api.dart b/lib/service/firebase_api.dart
index 07669db..a4233dd 100644
--- a/lib/service/firebase_api.dart
+++ b/lib/service/firebase_api.dart
@@ -35,6 +35,12 @@ class FirebaseApi with Logging {
   }
 
   Future<String> signInEmail(String email, String password) async {
+    if (email == null) {
+      throw Exception("Please type an email address");
+    }
+    if (password == null) {
+      throw Exception("Password too short");
+    }
     String rc = SIGN_IN_OK;
     try {
       userCredential = await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password);
diff --git a/lib/util/platform_purchase.dart b/lib/util/platform_purchase.dart
index 02cbf3d..57d8246 100644
--- a/lib/util/platform_purchase.dart
+++ b/lib/util/platform_purchase.dart
@@ -1,5 +1,8 @@
 import 'dart:async';
+import 'dart:io';
 
+import 'package:aitrainer_app/model/cache.dart';
+import 'package:aitrainer_app/model/product.dart';
 import 'package:aitrainer_app/service/logging.dart';
 import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
 
@@ -11,10 +14,14 @@ class PlatformPurchaseApi with Logging {
   StreamSubscription _conectionSubscription;
   String _platformVersion = 'Unknown';
   List<IAPItem> _items = [];
+  List getIAPItems() => _items;
   List<PurchasedItem> _purchases = [];
 
-  final List<String> _productLists = List();
-  /*   Platform.isAndroid
+  final List<String> _productList = List();
+
+  List getProductList() => _productList;
+
+  /* Platform.isAndroid
       ? [
           'android.test.purchased',
           'point_1000',
@@ -22,7 +29,7 @@ class PlatformPurchaseApi with Logging {
           'android.test.canceled',
         ]
       : ['com.cooni.point1000', 'com.cooni.point5000'];
- */
+  */
 
   factory PlatformPurchaseApi() {
     return _singleton;
@@ -30,27 +37,32 @@ class PlatformPurchaseApi with Logging {
 
   PlatformPurchaseApi._internal();
 
-  void close() {
+  Future<void> close() async {
     if (_conectionSubscription != null) {
       _conectionSubscription.cancel();
       _conectionSubscription = null;
     }
+    await FlutterInappPurchase.instance.endConnection;
   }
 
   // Platform messages are asynchronous, so we initialize in an async method.
   Future<void> initPurchasePlatformState() async {
+    if (_productList.length > 0) {
+      return;
+    }
+    log(" --- Init PurchasePlatform");
     String platformVersion;
     // Platform messages may fail, so we use a try/catch PlatformException.
     try {
       platformVersion = await FlutterInappPurchase.instance.platformVersion;
     } on Exception {
       platformVersion = 'Failed to get platform version for InAppPurchase.';
-      log(platformVersion);
+      log("PlatformVersion" + platformVersion);
     }
 
     // prepare
     var result = await FlutterInappPurchase.instance.initConnection;
-    log('result: $result');
+    log(' FlutterInappPurchase init result: $result');
 
     _platformVersion = platformVersion;
 
@@ -73,15 +85,57 @@ class PlatformPurchaseApi with Logging {
     _purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
       log('purchase-error: $purchaseError');
     });
+
+    getSubscriptions();
+  }
+
+  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);
+    });
+    _getSubscription();
+  }
+
+  void purchase(Product product) {
+    if (product == null) {
+      throw Exception("No product to purchase");
+    }
+    String productId = Platform.isAndroid ? product.productIdAndroid : product.productIdIos;
+    IAPItem selected;
+    for (var item in _items) {
+      if (item.productId == productId) {
+        selected = item;
+        log("Item to purchase: " + item.toString());
+      }
+    }
+
+    if (selected != null) {
+      requestPurchase(selected);
+    } else {
+      throw Exception("product " + productId + " not defined in the PlatformStore");
+    }
   }
 
   void requestPurchase(IAPItem item) {
     //FlutterInappPurchase.instance.requestPurchase(item.productId);
-    FlutterInappPurchase.instance.requestPurchase("WT_monthly");
+    FlutterInappPurchase.instance.requestPurchase(item.productId);
   }
 
-  Future _getProduct() async {
-    List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(_productLists);
+  Future _getSubscription() async {
+    List<IAPItem> items = await FlutterInappPurchase.instance.getSubscriptions(_productList);
     for (var item in items) {
       log('${item.toString()}');
       this._items.add(item);
diff --git a/lib/view/sales_page.dart b/lib/view/sales_page.dart
index ab73a98..c0cf855 100644
--- a/lib/view/sales_page.dart
+++ b/lib/view/sales_page.dart
@@ -1,4 +1,5 @@
 import 'package:aitrainer_app/bloc/sales/sales_bloc.dart';
+import 'package:aitrainer_app/service/logging.dart';
 import 'package:aitrainer_app/util/trans.dart';
 import 'package:aitrainer_app/widgets/app_bar_min.dart';
 import 'package:aitrainer_app/widgets/sales_button.dart';
@@ -8,121 +9,122 @@ import 'package:google_fonts/google_fonts.dart';
 import 'package:modal_progress_hud/modal_progress_hud.dart';
 
 // ignore: must_be_immutable
-class SalesPage extends StatelessWidget with Trans {
+class SalesPage extends StatelessWidget with Trans, Logging {
   @override
   Widget build(BuildContext context) {
     setContext(context);
-    return BlocProvider(
-        create: (context) => SalesBloc()..add(SalesLoad()),
-        child: BlocConsumer<SalesBloc, SalesState>(listener: (context, state) {
-          if (state is SalesError) {
-            Scaffold.of(context).showSnackBar(
-                SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
-          }
-        }, builder: (context, state) {
-          final salesBloc = BlocProvider.of<SalesBloc>(context);
-          return ModalProgressHUD(
-            child: salesWidget(salesBloc),
-            inAsyncCall: state is SalesLoading,
-            opacity: 0.5,
-            color: Colors.black54,
-            progressIndicator: CircularProgressIndicator(),
-          );
-        }));
+    return Scaffold(
+        appBar: AppBarMin(
+          back: true,
+        ),
+        body: BlocProvider(
+            create: (context) => SalesBloc()..add(SalesLoad()),
+            child: BlocConsumer<SalesBloc, SalesState>(listener: (context, state) {
+              if (state is SalesError) {
+                log("Error: " + state.message);
+                Scaffold.of(context).showSnackBar(
+                    SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
+              }
+            }, builder: (context, state) {
+              final salesBloc = BlocProvider.of<SalesBloc>(context);
+              return ModalProgressHUD(
+                child: salesWidget(salesBloc),
+                inAsyncCall: state is SalesLoading,
+                opacity: 0.5,
+                color: Colors.black54,
+                progressIndicator: CircularProgressIndicator(),
+              );
+            })));
   }
 
   Widget salesWidget(SalesBloc bloc) {
     final double mediaWidth = MediaQuery.of(context).size.width;
     final double imageWidth = (mediaWidth - 5) / 2;
-    return Scaffold(
-        appBar: AppBarMin(
-          back: true,
+    return Container(
+        decoration: BoxDecoration(
+          image: DecorationImage(
+            image: AssetImage('asset/image/WT_black_background.png'),
+            fit: BoxFit.cover,
+            alignment: Alignment.center,
+          ),
         ),
-        body: Container(
-            decoration: BoxDecoration(
-              image: DecorationImage(
-                image: AssetImage('asset/image/WT_black_background.png'),
-                fit: BoxFit.cover,
-                alignment: Alignment.center,
-              ),
+        child: CustomScrollView(scrollDirection: Axis.vertical, slivers: [
+          SliverList(
+              delegate: SliverChildListDelegate([
+            Divider(),
+            Container(
+                padding: EdgeInsets.only(left: 65, right: 65),
+                child: Text("Unleash Your Development Now!",
+                    textAlign: TextAlign.center,
+                    maxLines: 4,
+                    softWrap: true,
+                    style: GoogleFonts.archivoBlack(
+                      fontSize: 30,
+                      color: Colors.white,
+                      shadows: <Shadow>[
+                        Shadow(
+                          offset: Offset(5.0, 5.0),
+                          blurRadius: 12.0,
+                          color: Colors.black54,
+                        ),
+                        Shadow(
+                          offset: Offset(-3.0, 3.0),
+                          blurRadius: 12.0,
+                          color: Colors.black54,
+                        ),
+                      ],
+                    ))),
+            Divider(),
+            Container(
+                padding: EdgeInsets.only(left: 45, right: 45),
+                child: Text("Learn about your development, enjoy AI-driven predictions of all of your skills and bodyparts.",
+                    textAlign: TextAlign.left,
+                    maxLines: 4,
+                    softWrap: true,
+                    style: GoogleFonts.inter(
+                      fontSize: 16,
+                      color: Colors.white,
+                    ))),
+            SizedBox(
+              height: 50,
             ),
-            child: CustomScrollView(scrollDirection: Axis.vertical, slivers: [
-              SliverList(
-                  delegate: SliverChildListDelegate([
-                Divider(),
-                Container(
-                    padding: EdgeInsets.only(left: 65, right: 65),
-                    child: Text("Unleash Your Development Now!",
-                        textAlign: TextAlign.center,
-                        maxLines: 4,
-                        softWrap: true,
-                        style: GoogleFonts.archivoBlack(
-                          fontSize: 30,
-                          color: Colors.white,
-                          shadows: <Shadow>[
-                            Shadow(
-                              offset: Offset(5.0, 5.0),
-                              blurRadius: 12.0,
-                              color: Colors.black54,
-                            ),
-                            Shadow(
-                              offset: Offset(-3.0, 3.0),
-                              blurRadius: 12.0,
-                              color: Colors.black54,
-                            ),
-                          ],
-                        ))),
-                Divider(),
-                Container(
-                    padding: EdgeInsets.only(left: 45, right: 45),
-                    child: Text("Learn about your development, enjoy AI-driven predictions of all of your skills and bodyparts.",
-                        textAlign: TextAlign.left,
-                        maxLines: 4,
-                        softWrap: true,
-                        style: GoogleFonts.inter(
-                          fontSize: 16,
-                          color: Colors.white,
-                        ))),
-                SizedBox(
-                  height: 50,
-                ),
-              ])),
-              SliverGrid(
-                delegate: SliverChildListDelegate(getButtons(bloc)),
-                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
-                  crossAxisCount: 3,
-                  mainAxisSpacing: 10.0,
-                  crossAxisSpacing: 10.0,
-                  childAspectRatio: 0.55,
-                ),
-              ),
-              SliverList(
-                  delegate: SliverChildListDelegate([
-                SizedBox(
-                  height: 30,
-                ),
-                Container(
-                    padding: EdgeInsets.only(left: 55, right: 55),
-                    child: Text(
-                      "Subscription Conditions",
-                      style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white),
-                    )),
-                Divider(),
-                Container(
-                    padding: EdgeInsets.only(left: 55, right: 55),
-                    child: Text(
-                      "Payment will be charged to your account. Subscription automatically renews unless auto-renew is turned off at least 24 hourse before the end of the current period",
-                      style: GoogleFonts.inter(fontSize: 12, color: Colors.white),
-                    )),
-                Divider(),
-                Container(
-                    padding: EdgeInsets.only(left: 55, right: 55),
-                    child: Text(
-                      "Account will be charged for renewal within 24 hours prior to the end of the current period",
-                      style: GoogleFonts.inter(fontSize: 12, color: Colors.white),
-                    )),
-              ])),
-            ])));
+          ])),
+          SliverGrid(
+            delegate: SliverChildListDelegate(getButtons(bloc)),
+            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
+              crossAxisCount: 3,
+              mainAxisSpacing: 10.0,
+              crossAxisSpacing: 10.0,
+              childAspectRatio: 0.55,
+            ),
+          ),
+          SliverList(
+              delegate: SliverChildListDelegate([
+            SizedBox(
+              height: 30,
+            ),
+            Container(
+                padding: EdgeInsets.only(left: 55, right: 55),
+                child: Text(
+                  "Subscription Conditions",
+                  style: GoogleFonts.inter(fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white),
+                )),
+            Divider(),
+            Container(
+                padding: EdgeInsets.only(left: 55, right: 55),
+                child: Text(
+                  "Payment will be charged to your account. Subscription automatically renews unless auto-renew is turned off at least 24 hourse before the end of the current period",
+                  style: GoogleFonts.inter(fontSize: 12, color: Colors.white),
+                )),
+            Divider(),
+            Container(
+                padding: EdgeInsets.only(left: 55, right: 55),
+                child: Text(
+                  "Account will be charged for renewal within 24 hours prior to the end of the current period",
+                  style: GoogleFonts.inter(fontSize: 12, color: Colors.white),
+                )),
+          ])),
+        ]));
     ;
   }
 
@@ -141,7 +143,7 @@ class SalesPage extends StatelessWidget with Trans {
       }
       Widget button = SalesButton(
         title: title,
-        price: element.description + interval,
+        price: element.localizedPrice,
         desc1: "Development programs",
         desc2: "Suggestions based on your actual status",
         desc3: "Special customized training plans",
diff --git a/lib/widgets/app_bar.dart b/lib/widgets/app_bar.dart
index 23558a4..3f6a4fc 100644
--- a/lib/widgets/app_bar.dart
+++ b/lib/widgets/app_bar.dart
@@ -142,6 +142,9 @@ class _AppBarNav extends State<AppBarNav> with SingleTickerProviderStateMixin, C
       ExerciseRepository exerciseRepository = ExerciseRepository();
       exerciseRepository.getBaseExerciseFinishedPercent();
       percent = Cache().getPercentExercises();
+      if (percent == null || percent == -1) {
+        percent = 0;
+      }
     }
     int sizeExerciseList = Cache().getExercises() == null ? 0 : Cache().getExercises().length;
     if (sizeExerciseList == 0) {
diff --git a/lib/widgets/dialog_premium.dart b/lib/widgets/dialog_premium.dart
index 951e3f4..7c0eddc 100644
--- a/lib/widgets/dialog_premium.dart
+++ b/lib/widgets/dialog_premium.dart
@@ -160,7 +160,7 @@ class _DialogPremiumState extends State<DialogPremium> with Trans {
                 Align(
                     alignment: Alignment.center,
                     child: GestureDetector(
-                        onTap: widget.onTap ?? widget.onTap,
+                        onTap: () => Navigator.of(context).pushNamed("salesPage"),
                         child: Stack(
                           alignment: Alignment.center,
                           children: [
diff --git a/lib/widgets/home.dart b/lib/widgets/home.dart
index 0a46a95..4826c1c 100644
--- a/lib/widgets/home.dart
+++ b/lib/widgets/home.dart
@@ -2,12 +2,14 @@ import 'package:aitrainer_app/bloc/session/session_bloc.dart';
 import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
 import 'package:aitrainer_app/model/cache.dart';
 import 'package:aitrainer_app/service/logging.dart';
+import 'package:aitrainer_app/util/platform_purchase.dart';
 import 'package:aitrainer_app/view/login.dart';
 import 'package:aitrainer_app/view/menu_page.dart';
 import 'package:aitrainer_app/view/registration.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/scheduler.dart';
+import 'package:flutter/semantics.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'loading.dart';
@@ -85,4 +87,10 @@ class _HomePageState extends State<AitrainerHome> with Logging {
       }),
     );
   }
+
+  @override
+  void dispose() async {
+    super.dispose();
+    await PlatformPurchaseApi().close();
+  }
 }
diff --git a/lib/widgets/image_button.dart b/lib/widgets/image_button.dart
index f34dbdd..0ea40a7 100644
--- a/lib/widgets/image_button.dart
+++ b/lib/widgets/image_button.dart
@@ -53,6 +53,8 @@ class ImageButton extends StatelessWidget {
       top = height - (style.fontSize - 5) * text.length - 2 * left < 0 ? height - 2 * style.fontSize - 22 : height - style.fontSize - 37;
       //print("Top: " + top.toStringAsFixed(0) + " length: " + ((style.fontSize - 5) * text.length).toString());
     }
+    final double width = MediaQuery.of(context).size.width;
+    print("Mediawidth: " + width.toStringAsFixed(0));
     return Stack(alignment: AlignmentDirectional.bottomStart, children: [
       FlatButton(
         child: image == null
@@ -101,29 +103,12 @@ class ImageButton extends StatelessWidget {
                   ],
                 )),
           )),
-      /* Positioned(
-            top: top,
-            left: left,
-            child: Container(
-              height: width - 2 * left,
-              width: width - 2 * left,
-              child: InkWell(
-                onTap: onTap ?? onTap,
-                child: Text(
-                  text,
-                  maxLines: 2,
-                  style: style,
-                ),
-              ),
-              color: Colors.transparent,
-            ),
-          ), */
       Cache().hasPurchased
           ? Offstage()
           : Stack(alignment: Alignment.topCenter, children: [
               Positioned(
-                top: 20,
-                left: 20,
+                top: 10,
+                left: (width / 2 - 30) / 2 - 75,
                 child: this.isLocked
                     ? GestureDetector(
                         child: Image.asset(
diff --git a/lib/widgets/menu_page_widget.dart b/lib/widgets/menu_page_widget.dart
index bc12ebb..69c2685 100644
--- a/lib/widgets/menu_page_widget.dart
+++ b/lib/widgets/menu_page_widget.dart
@@ -8,12 +8,14 @@ import 'package:aitrainer_app/localization/app_localization.dart';
 import 'package:aitrainer_app/model/cache.dart';
 import 'package:aitrainer_app/model/workout_menu_tree.dart';
 import 'package:aitrainer_app/service/logging.dart';
+import 'package:aitrainer_app/util/not_found_exception.dart';
 import 'package:aitrainer_app/util/trans.dart';
 import 'package:aitrainer_app/widgets/dialog_common.dart';
 import 'package:badges/badges.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/painting.dart';
+import 'package:flutter/services.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:google_fonts/google_fonts.dart';
 
@@ -331,30 +333,30 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
     return returnCode;
   }
 
-  dynamic _getButtonImage(WorkoutMenuTree workoutTree, double cWidth, double cHeight) {
-    dynamic image;
-    try {
+  Widget _getButtonImage(WorkoutMenuTree workoutTree, double cWidth, double cHeight) {
+    Widget image;
+
+    if (workoutTree.imageName.startsWith('https')) {
       image = ClipRRect(
-          borderRadius: BorderRadius.circular(24),
-          child: Image.asset(
-            workoutTree.imageName,
-            height: 210,
-            errorBuilder: (context, error, stackTrace) {
-              String url = Cache.mediaUrl + 'images/' + workoutTree.imageName.substring(11);
-              Widget image = FadeInImage.assetNetwork(
-                placeholder: 'asset/image/dots.gif',
-                image: url,
-                height: 210,
-              );
-              return image;
-            },
+          borderRadius: BorderRadius.circular(24.0),
+          child: Container(
+            color: Colors.black87,
+            child: FadeInImage(
+              image: NetworkImage(workoutTree.imageName),
+              placeholder: AssetImage("asset/image/dots.gif"),
+            ),
           ));
-    } on Exception catch (_) {
-      String url = Cache.mediaUrl + '/images/' + workoutTree.imageName;
-      image = FadeInImage.assetNetwork(
-        placeholder: 'asset/image/dots.gif',
-        image: url,
-        height: 210,
+    } else {
+      image = Container(
+        //width: cWidth - 30,
+        //height: 210.0,
+        decoration: BoxDecoration(
+          image: DecorationImage(
+            fit: BoxFit.cover,
+            image: AssetImage(workoutTree.imageName),
+          ),
+          borderRadius: BorderRadius.all(Radius.circular(24.0)),
+        ),
       );
     }
 
@@ -365,6 +367,7 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
     String badgeKey = workoutMenuTree.nameEnglish;
     bool show = Cache().getBadges()[badgeKey] != null;
     int counter = Cache().getBadges()[badgeKey] != null ? Cache().getBadges()[badgeKey] : 0;
+    Widget buttonImage = _getButtonImage(workoutMenuTree, cWidth, cHeight);
     return Badge(
       padding: EdgeInsets.all(8),
       position: BadgePosition.topEnd(top: 3, end: 3),
@@ -377,7 +380,11 @@ class _MenuPageWidgetState extends State<MenuPageWidget> with Trans, Logging {
             color: Colors.white,
             fontSize: 16,
           )),
-      child: _getButtonImage(workoutMenuTree, cWidth, cHeight),
+      child: buttonImage == null
+          ? Container(
+              color: Colors.red,
+            )
+          : buttonImage,
     );
   }
 
diff --git a/pubspec.lock b/pubspec.lock
index 67b11f2..25edc20 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -369,7 +369,21 @@ packages:
       name: flutter_facebook_auth
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.0.2+2"
+    version: "2.0.0+1"
+  flutter_facebook_auth_platform_interface:
+    dependency: transitive
+    description:
+      name: flutter_facebook_auth_platform_interface
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.1"
+  flutter_facebook_auth_web:
+    dependency: transitive
+    description:
+      name: flutter_facebook_auth_web
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "1.0.6"
   flutter_form_bloc:
     dependency: "direct main"
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index f4720b9..961a9e3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -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.3+44
+version: 1.1.4+45
 
 environment:
   sdk: ">=2.7.0 <3.0.0"
@@ -55,7 +55,7 @@ dependencies:
   #firebase_analytics: ^6.2.0
   firebase_messaging: ^7.0.3
   firebase_auth: ^0.18.3
-  flutter_facebook_auth: ^1.0.2+2
+  flutter_facebook_auth: ^2.0.0+1
   flurry: ^0.0.7
 
   animated_widgets: ^1.0.6