Documente Academic
Documente Profesional
Documente Cultură
RAPORT
Lucrarea de laborator nr. 6
Programarea aplicatiilor mobile
Tema: Telemedicine - SPRINT2
A verificat:
asist. univ. C. Rusu
Chisinau 2020
Scopul lucrarii
Pentru designul ofert in laboratorul nr. 5 să se implementeze partea funcțională a proiectului conform
serviciului API descris mai jos.
Metodele oferite de Servicu:
• Auth (autentificare)
• Reg (inregistrare)
• UserProfie (extragerea avansată despre utilizatorul curent autentificat)
• UpdateUserProfile (NotImplemented) - nu cred că o voi implementa
• GetDocList (vizualizarea listei de medici activi in sistem)
• GetDoc (vizualizarea unui anumit medici activ in sistem)
• UserRequestConsultation (Adaugarea unei programari la medic)
1. Register
Server:
[API REG] POST
~/api/Register/UserReg
Header - Content-Type:application/x-www-form-urlencoded
Body
Content-Type:application/x-www-form-urlencoded
FullName=
Birthday= {FORMAT yyyy/MM/dd}
Email=
Phone=
Address=
Username=
Password=
Base64Photo {string:base64}=
call.enqueue(new Callback<UserReg>() {
@Override
public void onResponse(Call<UserReg> call, Response<UserReg> response) {
Toast.makeText(getApplicationContext(), "Este necesara logarea.",
Toast.LENGTH_SHORT).show();
startActivity(new Intent(getApplicationContext(), Login.class));
}
@Override
public void onFailure(Call<UserReg> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
Design:
RESULT
"Status": "SUCCESS",
"Message": "TOKEN" < - need to be saved for future usage.
}
Android:
(API.java)
@FormUrlEncoded
@POST("api/Login/UserAuth/")
Call<UserAuth> auth(
@Field("Email") String email,
@Field("Password") String password
);
(Login.java)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://81.180.72.17/")
.addConverterFactory(GsonConverterFactory.create())
.build();
call.enqueue(new Callback<UserAuth>() {
@Override
public void onResponse(Call<UserAuth> call, Response<UserAuth> response) {
if (response.body() != null) {
Log.e("TOKEN: ", response.body().getMessage());
SharedPreferences.Editor editor = getSharedPreferences("TOKEN",
MODE_PRIVATE).edit();
editor.putString("TOKEN", response.body().getMessage());
editor.apply();
startActivity(new Intent(getApplicationContext(), Home_screen.class));
} else {
Toast.makeText(getApplicationContext(), "Login sau Parola incorecta.",
Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<UserAuth> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
Design:
In cazul in care Login/Parola este gresita utilizatorul este informat. In caz contrar, de la server se va
primi token-ul, iar utilizatorul este redirictionat catre urmatoarea pagina.
3. Doctor List
Server:
[API DOC LIST] GET
~/api/Doctor/GetDoctorList
Header - Content-Type:application/x-www-form-urlencoded
token=TOKEN
RESULT
{
"DocId": 1,
"FullName": "Arseni Andrei",
"Specs": "Oculist",
"Address": "str. Vasile Alecsandri 45A",
"About": "Medic Oculist cu experienta de 12 ani in domeniu.",
"Stars": 4.2,
"Photo": "base64:string"
},
{
"DocId": 2,
"FullName": "Stratila Alina",
"Specs": "Pediatru",
"Address": "str. Mihai Eminescu 12/3",
"About": "Medic Pediatru cu experienta de 7 ani in domeniu.",
"Stars": 4.8,
"Photo": "base64:string"
},
Android:
(API.java)
@GET("api/Doctor/GetDoctorList/")
Call<List<API_Doctor_list>> docList(
@Header("token") String token,
@Header("Content-Type") String content_type
);
(Doctor_list.java)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://81.180.72.17/")
.addConverterFactory(GsonConverterFactory.create())
.build();
}
}
@Override
public void onFailure(Call<List<API_Doctor_list>> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
Design:
Fiecare field se genereaza apare pentru fiecare doctor in mod automat (cu ajutorul functie
structure()) vezi anexa.
4. Doc Info
Server:
[API DOC {id}] GET
~/api/Doctor/GetDoctor/1
Header - Content-Type:application/x-www-form-urlencoded
token=TOKEN
RESULT
{
"DocId": 1,
"FullName": "Arseni Andrei",
"Specs": "Oculist",
"Address": "str. Vasile Alecsandri 45A",
"About": "Medic Oculist cu experienta de 12 ani in domeniu.",
"Stars": 4.2,
"Photo": "base64:string"
},
Android:
(API.java)
@GET("api/Doctor/GetDoctor/{id}")
Call<API_DocInfo> docInfo(
@Path("id") Integer id,
@Header("token") String token,
@Header("Content-Type") String content_type
);
(Doctor_details.java)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://81.180.72.17/")
.addConverterFactory(GsonConverterFactory.create())
.build();
profile_image.setImageBitmap(decodedByte);
textView9.setText(response.body().getFullName());
textView10.setText(response.body().getSpecs());
textView7.setText(String.valueOf(response.body().getStars()));
descr.setText(response.body().getAbout());
textView8.setText(response.body().getAddress());
address = response.body().getAddress();
name = response.body().getFullName();
}
@Override
public void onFailure(Call<API_DocInfo> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
Design:
Am implement si GMap care afiseaza pe harta locatia. De aceasta determinarea Lat Long se ocupa
Geocoder (vezi anexa).
5. Consulatie Request
Server:
[API CONSULTATION REQUEST] POST
~/api/Doctor/AddConsultation
Header - Content-Type:application/x-www-form-urlencoded
token=TOKEN
RESULT
"ConsId": 1,
"Name": "",
"Disease": "",
"Address": "",
"Description": "",
"DocId": 5,
"IsConfirmed": false
}
Android:
(API.java)
@FormUrlEncoded
@POST("api/Doctor/AddConsultation/")
Call<ConsDet> approve(
@Field("ConsId") int consid,
@Field("Name") String name,
@Field("Disease") String disease,
@Field("Address") String address,
@Field("Description") String desc,
@Field("DocId") int docid,
@Field("IsConfirmed") Boolean bool
);
(Approve_notification.java)
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://81.180.72.17/")
.addConverterFactory(GsonConverterFactory.create())
.build();
call.enqueue(new Callback<ConsDet>() {
@Override
public void onResponse(Call<ConsDet> call, Response<ConsDet> response) {
Toast.makeText(getApplicationContext(), "Cerere plasata",
Toast.LENGTH_LONG).show();
startActivity(new Intent(getApplicationContext(), Home_screen.class));
}
@Override
public void onFailure(Call<ConsDet> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
Design:
Anexe:
API.java
package maxim.cebotari;
import android.content.SharedPreferences;
import java.util.List;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.POST;
import retrofit2.http.Path;
@FormUrlEncoded
@POST("api/Register/UserReg/")
Call<UserReg> register(
@Field("FullName") String fullname,
@Field("Birthday") String birthday,
@Field("Email") String email,
@Field("Phone") String phone,
@Field("Address") String address,
@Field("Username") String username,
@Field("Password") String password,
@Field("Base64Photo") String photo
);
@FormUrlEncoded
@POST("api/Login/UserAuth/")
Call<UserAuth> auth(
@Field("Email") String email,
@Field("Password") String password
);
@GET("api/Doctor/GetDoctorList/")
Call<List<API_Doctor_list>> docList(
@Header("token") String token,
@Header("Content-Type") String content_type
);
@GET("api/Doctor/GetDoctor/{id}")
Call<API_DocInfo> docInfo(
@Path("id") Integer id,
@Header("token") String token,
@Header("Content-Type") String content_type
);
@FormUrlEncoded
@POST("api/Doctor/AddConsultation/")
Call<ConsDet> approve(
@Field("ConsId") int consid,
@Field("Name") String name,
@Field("Disease") String disease,
@Field("Address") String address,
@Field("Description") String desc,
@Field("DocId") int docid,
@Field("IsConfirmed") Boolean bool
);
}
SignUp.java
package maxim.cebotari;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
Button btnNext;
ImageButton btnBack;
String photo =
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNMT0zfBA
AESQHjMAmi3AAAAABJRU5ErkJggg==";
EditText name, birthday, email, phone, address, username, password;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sign_up);
btnBack = findViewById(R.id.btnBack);
btnNext = findViewById(R.id.btnNext);
name = findViewById(R.id.name);
birthday = findViewById(R.id.birthday);
email = findViewById(R.id.email);
phone = findViewById(R.id.phone);
address = findViewById(R.id.address);
username = findViewById(R.id.username);
password = findViewById(R.id.password);
btnNext.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
while ((bytesRead = inputStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
}
catch (IOException e) {
e.printStackTrace();
}
bytes = output.toByteArray();
String encodedString = Base64.encodeToString(bytes, Base64.DEFAULT);
*/
call.enqueue(new Callback<UserReg>() {
@Override
public void onResponse(Call<UserReg> call, Response<UserReg> response) {
Toast.makeText(getApplicationContext(), "Este necesara logarea.",
Toast.LENGTH_SHORT).show();
startActivity(new Intent(getApplicationContext(), Login.class));
}
@Override
public void onFailure(Call<UserReg> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
});
btnBack.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(getApplicationContext(), MainActivity.class));
}
});
}
}
Login.java
package maxim.cebotari;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
Button login;
TextView signUp;
EditText editEmail, editPass;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
login = findViewById(R.id.login);
signUp = findViewById(R.id.signUp);
editEmail = findViewById(R.id.editEmail);
editPass = findViewById(R.id.editPass);
login.setOnClickListener(v -> {
if (response.body() != null) {
Log.e("TOKEN: ", response.body().getMessage());
SharedPreferences.Editor editor = getSharedPreferences("TOKEN",
MODE_PRIVATE).edit();
editor.putString("TOKEN", response.body().getMessage());
editor.apply();
startActivity(new Intent(getApplicationContext(), Home_screen.class));
} else {
Toast.makeText(getApplicationContext(), "Login sau Parola incorecta.",
Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<UserAuth> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
});
}
}
Home_Screen.java
package maxim.cebotari;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
Button btnRequest;
EditText name, desease, location, description;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_screen);
btnRequest = findViewById(R.id.btnRequest);
name = findViewById(R.id.name);
desease = findViewById(R.id.desease);
location = findViewById(R.id.location);
description = findViewById(R.id.description);
btnRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SharedPreferences.Editor editor = getSharedPreferences("Request", MODE_PRIVATE).edit();
editor.putString("name", name.getText().toString());
editor.putString("desease", desease.getText().toString());
editor.putString("location", location.getText().toString());
editor.putString("description", description.getText().toString());
editor.apply();
startActivity(new Intent(getApplicationContext(), Doctor_list.class));
}
});
}
}
Doctor_List.java
package maxim.cebotari;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.List;
import de.hdodenhof.circleimageview.CircleImageView;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
ConstraintLayout docSelect;
LinearLayout parentLayout;
CircleImageView profile_image;
TextView textView9, nota, textView10, address;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_doctor_list);
docSelect = findViewById(R.id.docSelect);
parentLayout = findViewById(R.id.parentLayout);
profile_image = findViewById(R.id.profile_image);
textView9 = findViewById(R.id.textView9);
nota = findViewById(R.id.nota);
textView10 = findViewById(R.id.textView10);
address = findViewById(R.id.address);
docSelect.setVisibility(View.GONE);
structure(
apiDoctorList.getDocId(),
apiDoctorList.getPhoto(),
apiDoctorList.getFullName(),
String.valueOf(apiDoctorList.getStars()),
apiDoctorList.getSpecs(),
apiDoctorList.getAddress());
}
}
@Override
public void onFailure(Call<List<API_Doctor_list>> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
void structure(int docID, String ph, String nam, String st, String spe, String loc){
ConstraintLayout doc = new ConstraintLayout(getApplicationContext());
doc.setLayoutParams(docSelect.getLayoutParams());
doc.setBackgroundColor(Color.WHITE);
photo.setImageBitmap(decodedByte);
doc.addView(photo);
TextView name = (TextView)getLayoutInflater().inflate(R.layout.namestyle, null);
name.setLayoutParams(textView9.getLayoutParams());
name.setText(nam);
doc.addView(name);
doc.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getBaseContext(), Doctor_details.class);
intent.putExtra("docID", String.valueOf(docID));
startActivity(intent);
}
});
parentLayout.addView(doc);
}
}
Doctor_details.java
package maxim.cebotari;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.os.Handler;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import java.io.IOException;
import java.util.List;
import de.hdodenhof.circleimageview.CircleImageView;
import okhttp3.internal.platform.Platform;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
Button btnRequest1;
TextView textView9, textView10, textView7, descr, textView8;
MapView gmap;
CircleImageView profile_image;
GoogleMap map;
String name, address;
Address locatie;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_doctor_details);
btnRequest1 = findViewById(R.id.btnRequest1);
textView9 = findViewById(R.id.textView9);
textView10 = findViewById(R.id.textView10);
textView7 = findViewById(R.id.textView7);
descr = findViewById(R.id.descr);
textView8 = findViewById(R.id.textView8);
gmap = findViewById(R.id.gmap);
profile_image = findViewById(R.id.profile_image);
gmap.onCreate(savedInstanceState);
gmap.getMapAsync(this);
btnRequest1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(getBaseContext(), Approve_notification.class);
intent.putExtra("docID", String.valueOf(docID));
startActivity(intent);
}
});
profile_image.setImageBitmap(decodedByte);
textView9.setText(response.body().getFullName());
textView10.setText(response.body().getSpecs());
textView7.setText(String.valueOf(response.body().getStars()));
descr.setText(response.body().getAbout());
textView8.setText(response.body().getAddress());
address = response.body().getAddress();
name = response.body().getFullName();
}
@Override
public void onFailure(Call<API_DocInfo> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
@Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
map.getUiSettings().setMyLocationButtonEnabled(false);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
Toast.makeText(getApplicationContext(), "Reject Permissions", Toast.LENGTH_SHORT).show();
return;
}
map.setMyLocationEnabled(true);
try {
MapsInitializer.initialize(getApplicationContext());
} catch (Exception e) {
e.printStackTrace();
}
@Override
public void onResume() {
super.onResume();
gmap.onResume();
}
}
Approve_notification.java
package maxim.cebotari;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import de.hdodenhof.circleimageview.CircleImageView;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_approve_notification);
name = findViewById(R.id.name);
desease = findViewById(R.id.desease);
location = findViewById(R.id.location);
description = findViewById(R.id.description);
docname = findViewById(R.id.textView9);
profile_image = findViewById(R.id.profile_image);
docspec = findViewById(R.id.textView10);
star = findViewById(R.id.textView7);
btnRequest2 = findViewById(R.id.btnRequest2);
cancelRequest = findViewById(R.id.cancelRequest);
profile_image.setImageBitmap(decodedByte);
docname.setText(response.body().getFullName());
docspec.setText(response.body().getSpecs());
star.setText(String.valueOf(response.body().getStars()));
docid = response.body().getDocId();
}
@Override
public void onFailure(Call<API_DocInfo> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
btnRequest2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
call.enqueue(new Callback<ConsDet>() {
@Override
public void onResponse(Call<ConsDet> call, Response<ConsDet> response) {
Toast.makeText(getApplicationContext(), "Cerere plasata",
Toast.LENGTH_LONG).show();
startActivity(new Intent(getApplicationContext(), Home_screen.class));
}
@Override
public void onFailure(Call<ConsDet> call, Throwable t) {
Toast.makeText(getApplicationContext(), t.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
});
cancelRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), "Canceled", Toast.LENGTH_SHORT).show();
startActivity(new Intent(getApplicationContext(), Home_screen.class));
}
});
}
}