setPresc(EthereumAddress doc, EthereumAddress pat,
191 | String privateKey, String prescription) async {
192 | if (await isAuthorized(doc, pat)) {
193 | Credentials key = EthPrivateKey.fromHex(privateKey);
194 |
195 | //obtain our contract from abi in json file
196 | final contract = await getContractPatient();
197 |
198 | // extract function from json file
199 | final function = contract.function("setPrescription");
200 |
201 | //send transaction using the our private key, function and contract
202 | await ethClient.sendTransaction(
203 | key,
204 | Transaction.callContract(
205 | contract: contract,
206 | function: function,
207 | parameters: [prescription, pat, doc]),
208 | chainId: 4);
209 | } else {
210 | Fluttertoast.showToast(msg: "You are not authorized");
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # MedRec
4 |
5 |
6 |
7 | Medical records need innovation. Patients leave data scattered across various jurisdictions as life events take them away from one provider’s data to another. In doing so, they lose easy access to past data, as the provider, not the patient, generally retains primary stewardship. Patients thus interact with records in a broken manner that reflects the nature of how these records are managed. Patients with a huge medical history across many hospitals should not have to keep their history in the form of huge Patients and providers may face significant hurdles in initiating data retrieval and sharing due to economic incentives that encourage “health information blocking”. In the age of online banking and social media, patients are increasingly willing, able and desirous of managing their data on the web and on the go. This work explores a blockchain structure with its backend based on a Rinkeby Test network using Ethereum for its data storage and a smart contract for its data logic. Medical Records are data with sensitive information, and hence using DAPPS with smart contracts ensures safety features essential such as Zero Downtime (i.e. the data associated with a patient is always ready to be fetched and updated), Privacy (A Patient's data should be secured and of limited accessibility to only the people closely associated with the patient), Complete data integrity (The data must not be changed by someone in no authority to do so). This MedRec blockchain implementation seeks to solve this vast fragmentation of patient data by bringing it together and organizing it in the form of a ledger while providing it with the benefits provided by blockchain and DAPPs.
8 |
9 | Hence, by implementing Medical records on the blockchain we achieve the following features which by other means could only be partially fulfilled or not fulfilled at all.
10 |
11 | 1. Non-Repudiation of Medical Records, i.e. once the prescription is received by a patient from a doctor, the transaction is stored digitally on the blockchain signed by the private keys of both the patient and the doctor, hence if either party refuses to claim the ownership of the transaction, it can be easily detected using the public key of both.
12 | 2. Only the authorized doctor can suggest a prescription that is to be added to the patient records.
13 | 3. The integrity that the prescription once added cannot be modified by any of the parties involved, i.e. the doctor, the patient or an attacker trying to harass the patient.
14 | 4. Automated transactions using smart contracts i.e. Once the patient authorizes a doctor to suggest a prescription, money is automatically transferred from the patient’s wallet to the patient contract and once the doctor sends a prescription, the money is transferred from the patient contract to the doctor’s wallet. The prescription to be sent is based on the mutual trust between the doctor and the patient and is not regulated by the application.
15 |
16 | 5. The contracts were created with vulnerabilities like Re-entrancy, transaction ordering, value underflow-overflow etc. in mind hence the application is safe to use under such circumstances if they shall prevail.
17 |
18 |
19 |
20 |
21 | ## Contents
22 |
23 | [Download APK](#Download-APK) • [How to Use](#how-to-use) • [Screenshots on Android](#screenshots-on-Android) • [Screenshots on Linux](#screenshots-on-Linux) • [Libraries & Tools Used](#libraries--tools-used) • [Folder Structure](#folder-structure) • [Routes](#routes) • [Main](#main) • [Contracts](#Solidity-Contracts)
24 |
25 |
26 |
27 |
28 | ## Download APK
29 | You can download the latest installable version of MedRec for Android from `Releases` or using this link: [MedRec.apk](https://github.com/Abhishekkr3003/MedRec/releases/download/v1.0.0/MedRec.apk)
30 |
31 |
32 | ## How to Use
33 |
34 | Steps working for Android, IOS, MacOS, Windows, Linux and Web.
35 |
36 | **Step 1:**
37 |
38 | Download or clone this repo by using the link below:
39 |
40 | ```
41 | https://github.com/Abhishekkr3003/MedRec.git
42 | ```
43 |
44 | **Step 2:**
45 |
46 | Go to project root and execute the following command in console to get the required dependencies (make sure you have flutter installed successfully):
47 |
48 | ```
49 | flutter pub get
50 | ```
51 |
52 | **Step 3:**
53 |
54 | Connect your device and run:
55 |
56 | ```
57 | flutter run
58 | ```
59 |
60 |
61 | ## Screenshots on Android
62 |
63 |
64 |
65 |  |
66 |  |
67 |  |
68 |
69 |
70 |  |
71 |  |
72 |  |
73 |
74 |
75 |  |
76 |  |
77 |
78 |
79 |
80 | ## Screenshots on Linux
81 |
82 |
83 |
84 |
85 |  |
86 |
87 |
88 |  |
89 |
90 |
91 |  |
92 |
93 |
94 |  |
95 |
96 |
97 |  |
98 |
99 |
100 |  |
101 |
102 |
103 |
104 |
105 | ## Libraries & Tools Used
106 |
107 | * [web3dart](https://github.com/xclud/web3dart)
108 | * [http](https://github.com/dart-lang/http)
109 | * [Cupertino_Icons](https://github.com/flutter/packages/tree/master/third_party/packages/cupertino_icons)
110 | * [font_awesome_flutter](https://github.com/fluttercommunity/font_awesome_flutter)
111 | * [FlutterToast](https://github.com/PonnamKarthik/FlutterToast)
112 | * [Google Fonts](https://github.com/material-foundation/google-fonts-flutter/)
113 |
114 | ## Folder Structure
115 | Here is the core folder structure which flutter provides.
116 |
117 | ```
118 | flutter-app/
119 | |- android
120 | |- assets
121 | |- build
122 | |- ios
123 | |- lib
124 | |- test
125 | |- linux
126 | |- macos
127 | |- test
128 | |- web
129 | |- windows
130 | ```
131 |
132 | Here is the folder structure we have been using in this project
133 |
134 | ```
135 | assets/
136 | |- contracts/
137 | |- doctor.json
138 | |- patient.json
139 | |- Icons/
140 | |- 1024.png
141 | |-images
142 | |-welcomeImage.png
143 |
144 | lib/
145 | |- Pages/
146 | |- doctor_home_page.dart
147 | |- login.dart
148 | |- patient_home_page.dart
149 | |- splash_screen.dart
150 | |- view_prescription.dart
151 |
152 | |- Utils/
153 | |- routes.dart
154 | |- routes.dart
155 |
156 | |- main.dart
157 | ```
158 |
159 | ## Routes
160 |
161 | This file contains all the routes for your application.
162 |
163 | ```dart
164 | import 'package:flutter/material.dart';
165 | import 'package:medrec/Pages/doctor_home_page.dart';
166 | import 'package:medrec/Pages/login.dart';
167 | import 'package:medrec/Pages/patient_home_page.dart';
168 |
169 | class MyRoutes {
170 | static const String loginPage = "/loginPage";
171 | static const String doctorHomePage = "/doctorHome";
172 | static const String patientHomePage = "/patientHome";
173 |
174 | static final routes = {
175 | loginPage: (context) => const LoginPage(),
176 | doctorHomePage: (context) => const DoctorHomePage(),
177 | patientHomePage: (context) => const PatientHomePage(),
178 | };
179 | }
180 |
181 | ```
182 |
183 | ## Main
184 |
185 | This is the starting point of the application. All the application level configurations are defined in this file i.e, theme, routes, title, orientation etc.
186 |
187 | ```dart
188 | import 'package:flutter/material.dart';
189 | import 'package:flutter/services.dart';
190 | import 'package:google_fonts/google_fonts.dart';
191 | import 'Pages/splash_screen.dart';
192 | import 'Utils/routes.dart';
193 |
194 | void main() {
195 | SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
196 | statusBarColor: Colors.black, statusBarIconBrightness: Brightness.light));
197 | runApp(const MyApp());
198 | }
199 |
200 | class MyApp extends StatelessWidget {
201 | const MyApp({Key? key}) : super(key: key);
202 |
203 | @override
204 | Widget build(BuildContext context) {
205 | return MaterialApp(
206 | debugShowCheckedModeBanner: false,
207 | theme: ThemeData(
208 | textTheme: GoogleFonts.poppinsTextTheme(
209 | Theme.of(context).textTheme,
210 | ),
211 | ),
212 | home: const Splash2(),
213 | routes: MyRoutes.routes,
214 | );
215 | }
216 | }
217 |
218 | ```
219 |
220 | ## Solidity Contracts
221 | [Doctor](https://github.com/Abhishekkr3003/MedRec/blob/main/solidity_contracts/doctor.sol)
222 |
223 |
224 | [Patient](https://github.com/Abhishekkr3003/MedRec/blob/main/solidity_contracts/patient.sol)
225 |
226 |
--------------------------------------------------------------------------------
/lib/Pages/view_prescription.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
4 |
5 | class ViewPrescription extends StatelessWidget {
6 | final int index;
7 | final List record;
8 | const ViewPrescription({
9 | Key? key,
10 | required this.index,
11 | required this.record,
12 | }) : super(key: key);
13 |
14 | @override
15 | Widget build(BuildContext context) {
16 | return Scaffold(
17 | backgroundColor: Colors.white,
18 | body: SafeArea(
19 | child: SingleChildScrollView(
20 | child: Padding(
21 | padding: const EdgeInsets.all(16.0),
22 | child: Column(
23 | mainAxisAlignment: MainAxisAlignment.center,
24 | crossAxisAlignment: CrossAxisAlignment.start,
25 | children: [
26 | Row(
27 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
28 | children: [
29 | SizedBox(
30 | width: MediaQuery.of(context).size.width - 100,
31 | child: Text(
32 | "Record #$index",
33 | style: const TextStyle(
34 | fontSize: 50, fontWeight: FontWeight.bold),
35 | ),
36 | ),
37 | IconButton(
38 | onPressed: () => Navigator.pop(context),
39 | icon: const Icon(CupertinoIcons.chevron_back),
40 | iconSize: 40,
41 | )
42 | ],
43 | ),
44 | Row(
45 | mainAxisAlignment: MainAxisAlignment.start,
46 | children: [
47 | const Icon(
48 | FontAwesomeIcons.clock,
49 | size: 15,
50 | color: Colors.grey,
51 | ),
52 | const SizedBox(
53 | width: 10,
54 | ),
55 | Text(
56 | record[0],
57 | style: Theme.of(context).textTheme.caption,
58 | ),
59 | ],
60 | ),
61 | Row(
62 | mainAxisAlignment: MainAxisAlignment.start,
63 | children: [
64 | const Icon(
65 | FontAwesomeIcons.userDoctor,
66 | size: 15,
67 | color: Colors.grey,
68 | ),
69 | const SizedBox(
70 | width: 10,
71 | ),
72 | SizedBox(
73 | width: MediaQuery.of(context).size.width - 100,
74 | // height: 30,
75 | child: Text(
76 | record[1],
77 | style: Theme.of(context).textTheme.caption,
78 | ),
79 | ),
80 | ],
81 | ),
82 | const Divider(
83 | thickness: 2,
84 | ),
85 | Center(
86 | child: Container(
87 | width: 200,
88 | height: 50,
89 | padding: const EdgeInsets.all(8),
90 | child: Row(
91 | mainAxisAlignment: MainAxisAlignment.center,
92 | children: const [
93 | Icon(
94 | FontAwesomeIcons.noteSticky,
95 | color: Colors.black,
96 | size: 25,
97 | ),
98 | Padding(
99 | padding: EdgeInsets.all(8.0),
100 | child: VerticalDivider(
101 | color: Colors.black,
102 | thickness: 1,
103 | ),
104 | ),
105 | Text(
106 | 'Notes',
107 | style: TextStyle(
108 | fontSize: 20,
109 | fontWeight: FontWeight.bold,
110 | color: Colors.black),
111 | ),
112 | ],
113 | ),
114 | ),
115 | ),
116 | Padding(
117 | padding: const EdgeInsets.all(8.0),
118 | child: Center(
119 | child: Text(
120 | record[2],
121 | textAlign: TextAlign.justify,
122 | ),
123 | ),
124 | ),
125 | const Divider(
126 | thickness: 2,
127 | ),
128 | Center(
129 | child: Container(
130 | width: 200,
131 | height: 50,
132 | padding: const EdgeInsets.all(8),
133 | child: Row(
134 | mainAxisAlignment: MainAxisAlignment.center,
135 | children: const [
136 | Icon(
137 | FontAwesomeIcons.scaleBalanced,
138 | color: Colors.black,
139 | size: 25,
140 | ),
141 | Padding(
142 | padding: EdgeInsets.all(8.0),
143 | child: VerticalDivider(
144 | color: Colors.black,
145 | thickness: 1,
146 | ),
147 | ),
148 | Text(
149 | 'Vitals',
150 | style: TextStyle(
151 | fontSize: 20,
152 | fontWeight: FontWeight.bold,
153 | color: Colors.black),
154 | ),
155 | ],
156 | ),
157 | ),
158 | ),
159 | Padding(
160 | padding: const EdgeInsets.all(8.0),
161 | child: Center(
162 | child: Text(
163 | record[3],
164 | textAlign: TextAlign.justify,
165 | ),
166 | ),
167 | ),
168 | const Divider(
169 | thickness: 2,
170 | ),
171 | Center(
172 | child: Container(
173 | width: 200,
174 | height: 50,
175 | padding: const EdgeInsets.all(8),
176 | child: Row(
177 | mainAxisAlignment: MainAxisAlignment.center,
178 | children: const [
179 | Icon(
180 | FontAwesomeIcons.tablets,
181 | color: Colors.black,
182 | size: 25,
183 | ),
184 | Padding(
185 | padding: EdgeInsets.all(8.0),
186 | child: VerticalDivider(
187 | color: Colors.black,
188 | thickness: 1,
189 | ),
190 | ),
191 | Text(
192 | 'Medicines',
193 | style: TextStyle(
194 | fontSize: 20,
195 | fontWeight: FontWeight.bold,
196 | color: Colors.black),
197 | ),
198 | ],
199 | ),
200 | ),
201 | ),
202 | Padding(
203 | padding: const EdgeInsets.all(8.0),
204 | child: Center(
205 | child: Text(
206 | record[4],
207 | textAlign: TextAlign.justify,
208 | ),
209 | ),
210 | ),
211 | const Divider(
212 | thickness: 2,
213 | ),
214 | Center(
215 | child: Container(
216 | width: 200,
217 | height: 50,
218 | padding: const EdgeInsets.all(8),
219 | child: Row(
220 | mainAxisAlignment: MainAxisAlignment.center,
221 | children: const [
222 | Icon(
223 | FontAwesomeIcons.message,
224 | color: Colors.black,
225 | size: 25,
226 | ),
227 | Padding(
228 | padding: EdgeInsets.all(8.0),
229 | child: VerticalDivider(
230 | color: Colors.black,
231 | thickness: 1,
232 | ),
233 | ),
234 | Text(
235 | 'Advice',
236 | style: TextStyle(
237 | fontSize: 20,
238 | fontWeight: FontWeight.bold,
239 | color: Colors.black),
240 | ),
241 | ],
242 | ),
243 | ),
244 | ),
245 | Padding(
246 | padding: const EdgeInsets.all(8.0),
247 | child: Center(
248 | child: Text(
249 | record[5],
250 | textAlign: TextAlign.justify,
251 | ),
252 | ),
253 | )
254 | ]),
255 | ),
256 | )));
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/lib/Pages/login.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:fluttertoast/fluttertoast.dart';
4 | import 'package:google_fonts/google_fonts.dart';
5 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
6 | import 'package:medrec/Utils/connector.dart';
7 | import 'package:medrec/Utils/routes.dart';
8 | import 'package:web3dart/web3dart.dart';
9 |
10 | bool adding = false;
11 |
12 | class LoginPage extends StatefulWidget {
13 | const LoginPage({Key? key}) : super(key: key);
14 |
15 | @override
16 | _LoginPageState createState() => _LoginPageState();
17 | }
18 |
19 | class _LoginPageState extends State {
20 | TextEditingController address = TextEditingController();
21 | TextEditingController privateKey = TextEditingController();
22 | TextEditingController role = TextEditingController();
23 | final _formKey = GlobalKey();
24 |
25 | _showPicker() {
26 | showModalBottomSheet(
27 | context: context,
28 | shape: const RoundedRectangleBorder(
29 | borderRadius: BorderRadius.vertical(top: Radius.circular(5.0))),
30 | builder: (BuildContext bc) {
31 | return SafeArea(
32 | child: Wrap(
33 | children: [
34 | const Padding(
35 | padding: EdgeInsets.fromLTRB(16, 8, 8, 8),
36 | child: Text(
37 | "Roles",
38 | style: TextStyle(fontSize: 40, fontWeight: FontWeight.bold),
39 | ),
40 | ),
41 | ListTile(
42 | leading: const Icon(
43 | CupertinoIcons.person_alt_circle,
44 | color: Colors.black,
45 | ),
46 | title: const Text(
47 | 'Patient',
48 | style:
49 | TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
50 | ),
51 | onTap: () {
52 | role.text = "Patient";
53 | setState(() {});
54 | Navigator.pop(context);
55 | }),
56 | ListTile(
57 | leading: const Icon(
58 | FontAwesomeIcons.userDoctor,
59 | color: Colors.black,
60 | ),
61 | title: const Text(
62 | 'Doctor',
63 | style:
64 | TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
65 | ),
66 | onTap: () {
67 | role.text = "Doctor";
68 | setState(() {});
69 | Navigator.pop(context);
70 | })
71 | ],
72 | ),
73 | );
74 | });
75 | }
76 |
77 | void moveToHome() async {
78 | bool result;
79 | if (_formKey.currentState!.validate()) {
80 | adding = true;
81 | setState(() {});
82 | if (role.text == "Patient") {
83 | try {
84 | result = await Connector.logInPatient(address.text, privateKey.text);
85 | if (!result) {
86 | Fluttertoast.showToast(msg: "Wrong credentials");
87 | setState(() {
88 | adding = false;
89 | });
90 | } else {
91 | Fluttertoast.showToast(msg: "Login Success");
92 | Connector.address = EthereumAddress.fromHex(address.text);
93 | Connector.key = privateKey.text;
94 | await Navigator.pushReplacementNamed(
95 | context, MyRoutes.patientHomePage);
96 | }
97 | } catch (e) {
98 | // print("here");
99 | // print(e);
100 | Fluttertoast.showToast(
101 | msg: "Oops! Something went wrong. Try Again...");
102 | // print('Error creating user: $e');
103 | setState(() {
104 | adding = false;
105 | });
106 | }
107 | adding = false;
108 | } else if (role.text == "Doctor") {
109 | try {
110 | result = await Connector.logInPatient(address.text, privateKey.text);
111 | if (!result) {
112 | Fluttertoast.showToast(msg: "Wrong credentials");
113 | setState(() {
114 | adding = false;
115 | });
116 | } else {
117 | Fluttertoast.showToast(msg: "Login Success");
118 | Connector.address = EthereumAddress.fromHex(address.text);
119 | Connector.key = privateKey.text;
120 | await Navigator.pushReplacementNamed(
121 | context, MyRoutes.doctorHomePage);
122 | }
123 | } catch (e) {
124 | Fluttertoast.showToast(
125 | msg: "Oops! Something went wrong. Try Again...");
126 | // print('Error creating user: $e');
127 | setState(() {
128 | adding = false;
129 | });
130 | }
131 | adding = false;
132 | }
133 | }
134 | }
135 |
136 | @override
137 | Widget build(BuildContext context) {
138 | return Material(
139 | color: Theme.of(context).canvasColor,
140 | child: Scaffold(
141 | body: SafeArea(
142 | child: SingleChildScrollView(
143 | child: Form(
144 | key: _formKey,
145 | child: Column(
146 | mainAxisAlignment: MainAxisAlignment.start,
147 | crossAxisAlignment: CrossAxisAlignment.start,
148 | children: [
149 | Padding(
150 | padding: const EdgeInsets.fromLTRB(0, 0, 0, 16),
151 | child: Center(
152 | child: ClipRRect(
153 | borderRadius: const BorderRadius.only(
154 | bottomLeft: Radius.circular(100),
155 | bottomRight: Radius.circular(100)),
156 | child: SizedBox(
157 | width: MediaQuery.of(context).size.width,
158 | height: MediaQuery.of(context).size.height / 3,
159 | child: Image.asset(
160 | "assets/images/welcomeImage.png",
161 | fit: BoxFit.cover,
162 | ),
163 | ),
164 | ),
165 | ),
166 | ),
167 | const SizedBox(
168 | height: 20.0,
169 | ),
170 | Center(
171 | child: Text(
172 | "Sign-In",
173 | style: GoogleFonts.lato(
174 | fontSize: 50, fontWeight: FontWeight.bold),
175 | ),
176 | ),
177 | Padding(
178 | padding: const EdgeInsets.fromLTRB(32, 32, 32, 32),
179 | child: CupertinoFormSection(
180 | backgroundColor: Colors.transparent,
181 | children: [
182 | CupertinoFormRow(
183 | //padding: EdgeInsets.only(left: 0),
184 | child: CupertinoTextFormFieldRow(
185 | style: GoogleFonts.poppins(),
186 | controller: address,
187 | placeholder: "Enter your Etherium Address",
188 | prefix: Text(
189 | "Address ",
190 | style: Theme.of(context).textTheme.caption,
191 | ),
192 | padding: const EdgeInsets.only(left: 0),
193 | keyboardType: TextInputType.emailAddress,
194 | validator: (value) {
195 | if (value!.isEmpty) {
196 | return "Address can't be empty";
197 | }
198 | return null;
199 | },
200 | ),
201 | ),
202 | CupertinoFormRow(
203 | //padding: EdgeInsets.only(left: 0),
204 | child: CupertinoTextFormFieldRow(
205 | style: GoogleFonts.poppins(),
206 | controller: privateKey,
207 | placeholder: "Enter your private key",
208 | prefix: Text(
209 | "Key ",
210 | style: Theme.of(context).textTheme.caption,
211 | ),
212 | padding: const EdgeInsets.only(left: 0),
213 | keyboardType: TextInputType.emailAddress,
214 | validator: (value) {
215 | if (value!.isEmpty) {
216 | return "Key can't be empty";
217 | }
218 | return null;
219 | },
220 | ),
221 | ),
222 | CupertinoTextFormFieldRow(
223 | style: GoogleFonts.poppins(),
224 | controller: role,
225 | onTap: _showPicker,
226 | placeholder: "Tap to Show Roles",
227 | validator: (value) {
228 | if (value!.isEmpty) {
229 | return "Role can't be empty";
230 | }
231 | return null;
232 | },
233 | decoration: const BoxDecoration(color: Colors.white),
234 | prefix: Text(
235 | "Role ",
236 | style: Theme.of(context).textTheme.caption,
237 | ),
238 | readOnly: true,
239 | ),
240 | ],
241 | ),
242 | ),
243 | Padding(
244 | padding: EdgeInsets.all(32),
245 | child: adding
246 | ? const Center(
247 | child: Padding(
248 | padding: EdgeInsets.only(top: 40),
249 | child: CupertinoActivityIndicator(
250 | radius: 20,
251 | ),
252 | ),
253 | )
254 | : Center(
255 | child: Container(
256 | width: 60,
257 | height: 60,
258 | decoration: BoxDecoration(
259 | color: Colors.black,
260 | borderRadius: BorderRadius.circular(50),
261 | boxShadow: [
262 | BoxShadow(
263 | color: Colors.grey.withOpacity(0.5),
264 | blurRadius: 7,
265 | offset: const Offset(
266 | 0, 3), // changes position of shadow
267 | ),
268 | ],
269 | ),
270 | child: IconButton(
271 | onPressed: () => moveToHome(),
272 | icon: const Icon(Icons.send_outlined),
273 | iconSize: 40,
274 | color: Colors.white,
275 | ),
276 | ),
277 | ),
278 | )
279 | ],
280 | ),
281 | ),
282 | ),
283 | ),
284 | ),
285 | );
286 | }
287 | }
288 |
--------------------------------------------------------------------------------
/pubspec.lock:
--------------------------------------------------------------------------------
1 | # Generated by pub
2 | # See https://dart.dev/tools/pub/glossary#lockfile
3 | packages:
4 | _fe_analyzer_shared:
5 | dependency: transitive
6 | description:
7 | name: _fe_analyzer_shared
8 | url: "https://pub.dartlang.org"
9 | source: hosted
10 | version: "40.0.0"
11 | analyzer:
12 | dependency: transitive
13 | description:
14 | name: analyzer
15 | url: "https://pub.dartlang.org"
16 | source: hosted
17 | version: "4.1.0"
18 | args:
19 | dependency: transitive
20 | description:
21 | name: args
22 | url: "https://pub.dartlang.org"
23 | source: hosted
24 | version: "2.0.0"
25 | async:
26 | dependency: transitive
27 | description:
28 | name: async
29 | url: "https://pub.dartlang.org"
30 | source: hosted
31 | version: "2.8.2"
32 | boolean_selector:
33 | dependency: transitive
34 | description:
35 | name: boolean_selector
36 | url: "https://pub.dartlang.org"
37 | source: hosted
38 | version: "2.1.0"
39 | build:
40 | dependency: transitive
41 | description:
42 | name: build
43 | url: "https://pub.dartlang.org"
44 | source: hosted
45 | version: "2.3.0"
46 | build_config:
47 | dependency: transitive
48 | description:
49 | name: build_config
50 | url: "https://pub.dartlang.org"
51 | source: hosted
52 | version: "1.0.0"
53 | built_collection:
54 | dependency: transitive
55 | description:
56 | name: built_collection
57 | url: "https://pub.dartlang.org"
58 | source: hosted
59 | version: "5.1.1"
60 | built_value:
61 | dependency: transitive
62 | description:
63 | name: built_value
64 | url: "https://pub.dartlang.org"
65 | source: hosted
66 | version: "8.3.2"
67 | characters:
68 | dependency: transitive
69 | description:
70 | name: characters
71 | url: "https://pub.dartlang.org"
72 | source: hosted
73 | version: "1.2.0"
74 | charcode:
75 | dependency: transitive
76 | description:
77 | name: charcode
78 | url: "https://pub.dartlang.org"
79 | source: hosted
80 | version: "1.3.1"
81 | checked_yaml:
82 | dependency: transitive
83 | description:
84 | name: checked_yaml
85 | url: "https://pub.dartlang.org"
86 | source: hosted
87 | version: "2.0.1"
88 | clock:
89 | dependency: transitive
90 | description:
91 | name: clock
92 | url: "https://pub.dartlang.org"
93 | source: hosted
94 | version: "1.1.0"
95 | code_builder:
96 | dependency: transitive
97 | description:
98 | name: code_builder
99 | url: "https://pub.dartlang.org"
100 | source: hosted
101 | version: "4.1.0"
102 | collection:
103 | dependency: transitive
104 | description:
105 | name: collection
106 | url: "https://pub.dartlang.org"
107 | source: hosted
108 | version: "1.16.0"
109 | convert:
110 | dependency: transitive
111 | description:
112 | name: convert
113 | url: "https://pub.dartlang.org"
114 | source: hosted
115 | version: "3.0.1"
116 | crypto:
117 | dependency: transitive
118 | description:
119 | name: crypto
120 | url: "https://pub.dartlang.org"
121 | source: hosted
122 | version: "3.0.2"
123 | cupertino_icons:
124 | dependency: "direct main"
125 | description:
126 | name: cupertino_icons
127 | url: "https://pub.dartlang.org"
128 | source: hosted
129 | version: "1.0.4"
130 | dart_style:
131 | dependency: transitive
132 | description:
133 | name: dart_style
134 | url: "https://pub.dartlang.org"
135 | source: hosted
136 | version: "2.2.3"
137 | fake_async:
138 | dependency: transitive
139 | description:
140 | name: fake_async
141 | url: "https://pub.dartlang.org"
142 | source: hosted
143 | version: "1.3.0"
144 | ffi:
145 | dependency: transitive
146 | description:
147 | name: ffi
148 | url: "https://pub.dartlang.org"
149 | source: hosted
150 | version: "1.2.1"
151 | file:
152 | dependency: transitive
153 | description:
154 | name: file
155 | url: "https://pub.dartlang.org"
156 | source: hosted
157 | version: "6.1.2"
158 | fixnum:
159 | dependency: transitive
160 | description:
161 | name: fixnum
162 | url: "https://pub.dartlang.org"
163 | source: hosted
164 | version: "1.0.1"
165 | flutter:
166 | dependency: "direct main"
167 | description: flutter
168 | source: sdk
169 | version: "0.0.0"
170 | flutter_lints:
171 | dependency: "direct dev"
172 | description:
173 | name: flutter_lints
174 | url: "https://pub.dartlang.org"
175 | source: hosted
176 | version: "2.0.1"
177 | flutter_test:
178 | dependency: "direct dev"
179 | description: flutter
180 | source: sdk
181 | version: "0.0.0"
182 | flutter_web_plugins:
183 | dependency: transitive
184 | description: flutter
185 | source: sdk
186 | version: "0.0.0"
187 | fluttertoast:
188 | dependency: "direct main"
189 | description:
190 | name: fluttertoast
191 | url: "https://pub.dartlang.org"
192 | source: hosted
193 | version: "8.0.9"
194 | font_awesome_flutter:
195 | dependency: "direct main"
196 | description:
197 | name: font_awesome_flutter
198 | url: "https://pub.dartlang.org"
199 | source: hosted
200 | version: "10.1.0"
201 | glob:
202 | dependency: transitive
203 | description:
204 | name: glob
205 | url: "https://pub.dartlang.org"
206 | source: hosted
207 | version: "2.0.2"
208 | google_fonts:
209 | dependency: "direct main"
210 | description:
211 | name: google_fonts
212 | url: "https://pub.dartlang.org"
213 | source: hosted
214 | version: "3.0.1"
215 | http:
216 | dependency: transitive
217 | description:
218 | name: http
219 | url: "https://pub.dartlang.org"
220 | source: hosted
221 | version: "0.13.4"
222 | http_parser:
223 | dependency: transitive
224 | description:
225 | name: http_parser
226 | url: "https://pub.dartlang.org"
227 | source: hosted
228 | version: "4.0.1"
229 | js:
230 | dependency: transitive
231 | description:
232 | name: js
233 | url: "https://pub.dartlang.org"
234 | source: hosted
235 | version: "0.6.4"
236 | json_annotation:
237 | dependency: transitive
238 | description:
239 | name: json_annotation
240 | url: "https://pub.dartlang.org"
241 | source: hosted
242 | version: "4.5.0"
243 | json_rpc_2:
244 | dependency: transitive
245 | description:
246 | name: json_rpc_2
247 | url: "https://pub.dartlang.org"
248 | source: hosted
249 | version: "3.0.1"
250 | lints:
251 | dependency: transitive
252 | description:
253 | name: lints
254 | url: "https://pub.dartlang.org"
255 | source: hosted
256 | version: "2.0.0"
257 | logging:
258 | dependency: transitive
259 | description:
260 | name: logging
261 | url: "https://pub.dartlang.org"
262 | source: hosted
263 | version: "1.0.2"
264 | matcher:
265 | dependency: transitive
266 | description:
267 | name: matcher
268 | url: "https://pub.dartlang.org"
269 | source: hosted
270 | version: "0.12.11"
271 | material_color_utilities:
272 | dependency: transitive
273 | description:
274 | name: material_color_utilities
275 | url: "https://pub.dartlang.org"
276 | source: hosted
277 | version: "0.1.4"
278 | meta:
279 | dependency: transitive
280 | description:
281 | name: meta
282 | url: "https://pub.dartlang.org"
283 | source: hosted
284 | version: "1.7.0"
285 | package_config:
286 | dependency: transitive
287 | description:
288 | name: package_config
289 | url: "https://pub.dartlang.org"
290 | source: hosted
291 | version: "2.0.2"
292 | path:
293 | dependency: transitive
294 | description:
295 | name: path
296 | url: "https://pub.dartlang.org"
297 | source: hosted
298 | version: "1.8.1"
299 | path_provider:
300 | dependency: transitive
301 | description:
302 | name: path_provider
303 | url: "https://pub.dartlang.org"
304 | source: hosted
305 | version: "2.0.10"
306 | path_provider_android:
307 | dependency: transitive
308 | description:
309 | name: path_provider_android
310 | url: "https://pub.dartlang.org"
311 | source: hosted
312 | version: "2.0.14"
313 | path_provider_ios:
314 | dependency: transitive
315 | description:
316 | name: path_provider_ios
317 | url: "https://pub.dartlang.org"
318 | source: hosted
319 | version: "2.0.9"
320 | path_provider_linux:
321 | dependency: transitive
322 | description:
323 | name: path_provider_linux
324 | url: "https://pub.dartlang.org"
325 | source: hosted
326 | version: "2.1.6"
327 | path_provider_macos:
328 | dependency: transitive
329 | description:
330 | name: path_provider_macos
331 | url: "https://pub.dartlang.org"
332 | source: hosted
333 | version: "2.0.6"
334 | path_provider_platform_interface:
335 | dependency: transitive
336 | description:
337 | name: path_provider_platform_interface
338 | url: "https://pub.dartlang.org"
339 | source: hosted
340 | version: "2.0.4"
341 | path_provider_windows:
342 | dependency: transitive
343 | description:
344 | name: path_provider_windows
345 | url: "https://pub.dartlang.org"
346 | source: hosted
347 | version: "2.0.6"
348 | platform:
349 | dependency: transitive
350 | description:
351 | name: platform
352 | url: "https://pub.dartlang.org"
353 | source: hosted
354 | version: "3.1.0"
355 | plugin_platform_interface:
356 | dependency: transitive
357 | description:
358 | name: plugin_platform_interface
359 | url: "https://pub.dartlang.org"
360 | source: hosted
361 | version: "2.1.2"
362 | pointycastle:
363 | dependency: transitive
364 | description:
365 | name: pointycastle
366 | url: "https://pub.dartlang.org"
367 | source: hosted
368 | version: "3.6.0"
369 | process:
370 | dependency: transitive
371 | description:
372 | name: process
373 | url: "https://pub.dartlang.org"
374 | source: hosted
375 | version: "4.2.4"
376 | pub_semver:
377 | dependency: transitive
378 | description:
379 | name: pub_semver
380 | url: "https://pub.dartlang.org"
381 | source: hosted
382 | version: "2.1.1"
383 | pubspec_parse:
384 | dependency: transitive
385 | description:
386 | name: pubspec_parse
387 | url: "https://pub.dartlang.org"
388 | source: hosted
389 | version: "1.2.0"
390 | sky_engine:
391 | dependency: transitive
392 | description: flutter
393 | source: sdk
394 | version: "0.0.99"
395 | source_span:
396 | dependency: transitive
397 | description:
398 | name: source_span
399 | url: "https://pub.dartlang.org"
400 | source: hosted
401 | version: "1.8.2"
402 | stack_trace:
403 | dependency: transitive
404 | description:
405 | name: stack_trace
406 | url: "https://pub.dartlang.org"
407 | source: hosted
408 | version: "1.10.0"
409 | stream_channel:
410 | dependency: transitive
411 | description:
412 | name: stream_channel
413 | url: "https://pub.dartlang.org"
414 | source: hosted
415 | version: "2.1.0"
416 | stream_transform:
417 | dependency: transitive
418 | description:
419 | name: stream_transform
420 | url: "https://pub.dartlang.org"
421 | source: hosted
422 | version: "2.0.0"
423 | string_scanner:
424 | dependency: transitive
425 | description:
426 | name: string_scanner
427 | url: "https://pub.dartlang.org"
428 | source: hosted
429 | version: "1.1.0"
430 | term_glyph:
431 | dependency: transitive
432 | description:
433 | name: term_glyph
434 | url: "https://pub.dartlang.org"
435 | source: hosted
436 | version: "1.2.0"
437 | test_api:
438 | dependency: transitive
439 | description:
440 | name: test_api
441 | url: "https://pub.dartlang.org"
442 | source: hosted
443 | version: "0.4.9"
444 | typed_data:
445 | dependency: transitive
446 | description:
447 | name: typed_data
448 | url: "https://pub.dartlang.org"
449 | source: hosted
450 | version: "1.3.1"
451 | uuid:
452 | dependency: transitive
453 | description:
454 | name: uuid
455 | url: "https://pub.dartlang.org"
456 | source: hosted
457 | version: "3.0.6"
458 | vector_math:
459 | dependency: transitive
460 | description:
461 | name: vector_math
462 | url: "https://pub.dartlang.org"
463 | source: hosted
464 | version: "2.1.2"
465 | watcher:
466 | dependency: transitive
467 | description:
468 | name: watcher
469 | url: "https://pub.dartlang.org"
470 | source: hosted
471 | version: "1.0.1"
472 | web3dart:
473 | dependency: "direct main"
474 | description:
475 | name: web3dart
476 | url: "https://pub.dartlang.org"
477 | source: hosted
478 | version: "2.3.5"
479 | win32:
480 | dependency: transitive
481 | description:
482 | name: win32
483 | url: "https://pub.dartlang.org"
484 | source: hosted
485 | version: "2.6.1"
486 | xdg_directories:
487 | dependency: transitive
488 | description:
489 | name: xdg_directories
490 | url: "https://pub.dartlang.org"
491 | source: hosted
492 | version: "0.2.0+1"
493 | yaml:
494 | dependency: transitive
495 | description:
496 | name: yaml
497 | url: "https://pub.dartlang.org"
498 | source: hosted
499 | version: "3.1.1"
500 | sdks:
501 | dart: ">=2.17.1 <3.0.0"
502 | flutter: ">=2.10.0-0"
503 |
--------------------------------------------------------------------------------
/lib/Pages/patient_home_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:fluttertoast/fluttertoast.dart';
4 | import 'package:font_awesome_flutter/font_awesome_flutter.dart';
5 | import 'package:medrec/Pages/view_prescription.dart';
6 | import 'package:medrec/Utils/connector.dart';
7 | import 'package:medrec/Utils/routes.dart';
8 | import 'package:web3dart/credentials.dart';
9 |
10 | class PatientHomePage extends StatefulWidget {
11 | const PatientHomePage({Key? key}) : super(key: key);
12 |
13 | @override
14 | State createState() => _PatientHomePageState();
15 | }
16 |
17 | class _PatientHomePageState extends State {
18 | TextEditingController doctorAddress = TextEditingController();
19 | bool showLoading = true;
20 | List> prescriptions = [];
21 | void setAuthorization() async {
22 | if (doctorAddress.text.length < 40) {
23 | Fluttertoast.showToast(msg: "Wrong Address");
24 | return;
25 | }
26 | bool isAuthorized = await Connector.addAuthorization(
27 | EthereumAddress.fromHex(doctorAddress.text),
28 | Connector.address,
29 | Connector.key);
30 | if (!isAuthorized) {
31 | Fluttertoast.showToast(msg: "Authorization Failed");
32 | } else {
33 | Fluttertoast.showToast(
34 | msg: "Doctor is now authorized to give you prescription.");
35 | doctorAddress.clear();
36 | }
37 | }
38 |
39 | void getPrescriptions() async {
40 | setState(() {
41 | showLoading = true;
42 | });
43 | List result = await Connector.getPresc(Connector.address);
44 | for (var element in result) {
45 | prescriptions.add(element.toString().split('#'));
46 | }
47 | prescriptions = prescriptions.reversed.toList();
48 | setState(() {
49 | showLoading = false;
50 | });
51 | }
52 |
53 | _showPickerAuthorization() {
54 | showModalBottomSheet(
55 | isScrollControlled: true,
56 | shape: const RoundedRectangleBorder(
57 | borderRadius: BorderRadius.vertical(top: Radius.circular(25.0))),
58 | context: context,
59 | builder: (BuildContext bc) {
60 | return SingleChildScrollView(
61 | child: Padding(
62 | padding: MediaQuery.of(context).viewInsets,
63 | child: Column(
64 | mainAxisSize: MainAxisSize.min,
65 | children: [
66 | const Text(
67 | "Authorize Doctor",
68 | style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
69 | ),
70 | CupertinoFormSection(children: [
71 | CupertinoFormRow(
72 | //padding: EdgeInsets.only(left: 0),
73 | child: CupertinoTextFormFieldRow(
74 | controller: doctorAddress,
75 | // obscureText: true,
76 | placeholder: "Enter Doctor's Address",
77 | // prefix: "Email".text.make(),
78 | padding: const EdgeInsets.only(left: 0),
79 | keyboardType: TextInputType.emailAddress,
80 | validator: (value) {
81 | if (value!.isEmpty) {
82 | return "Address can't be empty";
83 | }
84 | return null;
85 | },
86 | prefix: Text(
87 | 'Address | ',
88 | style: Theme.of(context).textTheme.caption,
89 | ),
90 | ),
91 | ),
92 | InkWell(
93 | onTap: () async {
94 | setAuthorization();
95 | Navigator.pop(context);
96 | doctorAddress.clear();
97 | },
98 | child: const SizedBox(
99 | height: 50,
100 | child: Center(
101 | child: Text(
102 | "Submit",
103 | style: TextStyle(
104 | fontSize: 20,
105 | ),
106 | ),
107 | )))
108 | ])
109 | ],
110 | ),
111 | ),
112 | );
113 | });
114 | }
115 |
116 | @override
117 | void initState() {
118 | getPrescriptions();
119 | super.initState();
120 | }
121 |
122 | @override
123 | Widget build(BuildContext context) {
124 | return Scaffold(
125 | floatingActionButton: InkWell(
126 | onTap: () => _showPickerAuthorization(),
127 | child: Container(
128 | width: (MediaQuery.of(context).size.width / 1.5),
129 | height: 50,
130 | decoration: BoxDecoration(
131 | color: Colors.black,
132 | borderRadius: BorderRadius.circular(50),
133 | boxShadow: [
134 | BoxShadow(
135 | color: Colors.grey.withOpacity(0.5),
136 | blurRadius: 7,
137 | offset: const Offset(0, 3), // changes position of shadow
138 | ),
139 | ],
140 | ),
141 | child: Padding(
142 | padding: const EdgeInsets.all(8.0),
143 | child: Row(
144 | mainAxisAlignment: MainAxisAlignment.center,
145 | children: const [
146 | Icon(
147 | FontAwesomeIcons.userDoctor,
148 | color: Colors.white,
149 | size: 20,
150 | ),
151 | Padding(
152 | padding: EdgeInsets.all(8.0),
153 | child: VerticalDivider(
154 | color: Colors.white,
155 | thickness: 1,
156 | ),
157 | ),
158 | Text(
159 | 'Authorize Doctor',
160 | style: TextStyle(
161 | // fontSize: 20,
162 | fontWeight: FontWeight.bold,
163 | color: Colors.white),
164 | ),
165 | ],
166 | ),
167 | ),
168 | ),
169 | ),
170 | backgroundColor: Colors.white,
171 | body: SafeArea(
172 | child: SingleChildScrollView(
173 | child: Column(
174 | mainAxisAlignment: MainAxisAlignment.start,
175 | crossAxisAlignment: CrossAxisAlignment.start,
176 | children: [
177 | Container(
178 | width: MediaQuery.of(context).size.width,
179 | height: MediaQuery.of(context).size.height / 8,
180 | padding: const EdgeInsets.all(8),
181 | decoration: const BoxDecoration(
182 | color: Colors.black,
183 | borderRadius: BorderRadius.only(
184 | topLeft: Radius.circular(0),
185 | bottomLeft: Radius.circular(50),
186 | topRight: Radius.circular(0),
187 | bottomRight: Radius.circular(50),
188 | ),
189 | ),
190 | child: Row(
191 | crossAxisAlignment: CrossAxisAlignment.center,
192 | mainAxisAlignment: MainAxisAlignment.center,
193 | children: const [
194 | Icon(
195 | CupertinoIcons.person_circle,
196 | color: Colors.white,
197 | size: 40,
198 | ),
199 | VerticalDivider(
200 | color: Colors.white,
201 | // thickness: 5,
202 | ),
203 | Center(
204 | child: Text(
205 | 'Patient Panel',
206 | style: TextStyle(
207 | fontSize: 40,
208 | fontWeight: FontWeight.bold,
209 | color: Colors.white),
210 | ),
211 | ),
212 | ],
213 | ),
214 | ),
215 | Padding(
216 | padding: const EdgeInsets.fromLTRB(8, 16, 8, 16),
217 | child: Row(
218 | mainAxisAlignment: MainAxisAlignment.center,
219 | children: [
220 | Container(
221 | width: MediaQuery.of(context).size.width * 0.7,
222 | padding: const EdgeInsets.all(16),
223 | decoration: BoxDecoration(
224 | color: Colors.green.shade50,
225 | borderRadius: BorderRadius.circular(20),
226 | boxShadow: [
227 | BoxShadow(
228 | color: Colors.grey.withOpacity(0.5),
229 | blurRadius: 7,
230 | offset: const Offset(
231 | 0, 3), // changes position of shadow
232 | ),
233 | ],
234 | ),
235 | child: Center(
236 | child: Text(
237 | Connector.address.toString(),
238 | style: TextStyle(
239 | fontSize:
240 | (MediaQuery.of(context).size.width * 0.02),
241 | fontWeight: FontWeight.bold,
242 | color: Colors.green),
243 | ),
244 | ),
245 | ),
246 | const SizedBox(
247 | width: 10,
248 | ),
249 | InkWell(
250 | onTap: () {
251 | Connector.key = "";
252 | Navigator.popAndPushNamed(context, MyRoutes.loginPage);
253 | },
254 | child: Container(
255 | width: MediaQuery.of(context).size.width * 0.2,
256 | padding: const EdgeInsets.all(16),
257 | decoration: BoxDecoration(
258 | color: Colors.red.shade50,
259 | borderRadius: BorderRadius.circular(20),
260 | boxShadow: [
261 | BoxShadow(
262 | color: Colors.grey.withOpacity(0.5),
263 | blurRadius: 7,
264 | offset: const Offset(
265 | 0, 3), // changes position of shadow
266 | ),
267 | ],
268 | ),
269 | child: Center(
270 | child: Text(
271 | "Logout",
272 | style: TextStyle(
273 | fontSize:
274 | (MediaQuery.of(context).size.width * 0.02),
275 | // fontWeight: FontWeight.bold,
276 | color: Colors.red),
277 | ),
278 | ),
279 | ),
280 | ),
281 | ],
282 | ),
283 | ),
284 | Center(
285 | child: Container(
286 | width: MediaQuery.of(context).size.width,
287 | height: 50,
288 | padding: const EdgeInsets.all(8),
289 | child: Row(
290 | mainAxisAlignment: MainAxisAlignment.center,
291 | children: const [
292 | Icon(
293 | FontAwesomeIcons.timeline,
294 | color: Colors.black,
295 | size: 25,
296 | ),
297 | Padding(
298 | padding: EdgeInsets.all(8.0),
299 | child: VerticalDivider(
300 | color: Colors.black,
301 | thickness: 1,
302 | ),
303 | ),
304 | Text(
305 | 'Medical History',
306 | style: TextStyle(
307 | fontSize: 20,
308 | fontWeight: FontWeight.bold,
309 | color: Colors.black),
310 | ),
311 | ],
312 | ),
313 | ),
314 | ),
315 | (showLoading == false && prescriptions.isNotEmpty)
316 | ? ListView.builder(
317 | itemCount: prescriptions.length,
318 | shrinkWrap: true,
319 | itemBuilder: (BuildContext context, int index) {
320 | return InkWell(
321 | onTap: () async {
322 | await Navigator.push(
323 | context,
324 | MaterialPageRoute(
325 | builder: (context) => ViewPrescription(
326 | index: index + 1,
327 | record: prescriptions[index])));
328 | },
329 | child: Padding(
330 | padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
331 | child: Container(
332 | // margin: EdgeInsets.all(16),
333 | // height: 100,
334 | padding: const EdgeInsets.all(16),
335 | decoration: BoxDecoration(
336 | color: Colors.white,
337 | borderRadius: BorderRadius.circular(15),
338 | boxShadow: [
339 | BoxShadow(
340 | color: Colors.grey.withOpacity(0.5),
341 | blurRadius: 7,
342 | offset: const Offset(
343 | 0, 3), // changes position of shadow
344 | ),
345 | ],
346 | ),
347 | child: Row(
348 | children: [
349 | Padding(
350 | padding:
351 | const EdgeInsets.only(right: 8.0),
352 | child: ClipRRect(
353 | borderRadius: BorderRadius.circular(5),
354 | child: Container(
355 | color: Colors.black,
356 | child: Text(
357 | " ${index + 1} ",
358 | style: const TextStyle(
359 | color: Colors.white,
360 | ),
361 | ),
362 | ),
363 | ),
364 | ),
365 | const VerticalDivider(
366 | thickness: 2,
367 | ),
368 | Column(
369 | crossAxisAlignment:
370 | CrossAxisAlignment.start,
371 | children: [
372 | Row(
373 | mainAxisAlignment:
374 | MainAxisAlignment.start,
375 | children: [
376 | const Icon(
377 | FontAwesomeIcons.clock,
378 | size: 15,
379 | // color: Colors.grey,
380 | ),
381 | const SizedBox(
382 | width: 10,
383 | ),
384 | Text(
385 | prescriptions[index][0],
386 | // style:
387 | // Theme.of(context).textTheme.caption,
388 | ),
389 | ],
390 | ),
391 | Row(
392 | mainAxisAlignment:
393 | MainAxisAlignment.start,
394 | children: [
395 | const Icon(
396 | FontAwesomeIcons.userDoctor,
397 | size: 15,
398 | color: Colors.grey,
399 | ),
400 | const SizedBox(
401 | width: 10,
402 | ),
403 | SizedBox(
404 | width: MediaQuery.of(context)
405 | .size
406 | .width -
407 | 150,
408 | // height: 30,
409 | child: Text(
410 | prescriptions[index][1],
411 | style: Theme.of(context)
412 | .textTheme
413 | .caption,
414 | ),
415 | ),
416 | ],
417 | ),
418 | ],
419 | )
420 | ],
421 | )),
422 | ),
423 | );
424 | },
425 | )
426 | : showLoading == true
427 | ? const Center(
428 | child: Padding(
429 | padding: EdgeInsets.only(top: 40),
430 | child: CupertinoActivityIndicator(
431 | radius: 20,
432 | ),
433 | ),
434 | )
435 | : const Padding(
436 | padding: EdgeInsets.only(top: 32.0, left: 16),
437 | child: Text(
438 | "No Medical History!",
439 | style: TextStyle(
440 | fontSize: 70,
441 | fontWeight: FontWeight.bold,
442 | color: Colors.grey),
443 | ),
444 | ),
445 | ],
446 | ),
447 | ),
448 | ),
449 | );
450 | }
451 | }
452 |
--------------------------------------------------------------------------------