diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml index b0a818a..a72df15 100644 --- a/.idea/deploymentTargetDropDown.xml +++ b/.idea/deploymentTargetDropDown.xml @@ -7,11 +7,11 @@ - + - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 773fe0f..0b290cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -6,4 +6,11 @@ + + + \ No newline at end of file diff --git a/Backend_HandyHelper/index.js b/Backend_HandyHelper/index.js index 88a354f..0111aea 100644 --- a/Backend_HandyHelper/index.js +++ b/Backend_HandyHelper/index.js @@ -380,6 +380,198 @@ app.put('/users/:username/contact', (req, res) => { }); }); +// Define a route to retrieve the requests +app.get('/requests', (req, res) => { + // Query to retrieve the requests + const query = `SELECT post.title, post.initial_price, post.content, post.service_date, users.username, users.rating FROM apply INNER JOIN post ON apply.post_id = post.id INNER JOIN users ON apply.national_id = users.national_id`; + + // Execute the query + connection.query(query, (error, results) => { + if (error) { + console.error('Error retrieving requests:', error); + res.status(500).json({ error: 'Failed to retrieve requests' }); + } else { + res.json(results); + } + }); +}); + +// API endpoint to retrieve the number of applications for each request +app.get('/numOfApplicants', (req, res) => { + const query = ` + SELECT post.id, post.title, COUNT(apply.post_id) AS num_applications + FROM post + LEFT JOIN apply ON post.id = apply.post_id AND apply.accepted_status <> 'R' + GROUP BY post.id, post.title + `; + + connection.query(query, (err, results) => { + if (err) { + console.error('Error executing query:', err); + res.status(500).json({ error: 'An error occurred' }); + } else { + res.json(results); + } + }); + }); + + app.get('/combinedData/:nationalID', (req, res) => { + const nationalID = req.params.nationalID; + + const query = ` + SELECT + post.title, post.initial_price, post.content, post.service_date, post.id, + users.username, users.rating, + COUNT(CASE WHEN apply.accepted_status <> 'R' THEN 1 END) AS num_applications, + EXISTS ( + SELECT 1 + FROM apply + WHERE apply.post_id = post.id + AND apply.accepted_status = 'A' + LIMIT 1 + ) AS has_accepted_applicant + FROM + post + LEFT JOIN + apply ON post.id = apply.post_id + INNER JOIN + users ON post.national_id = users.national_id + WHERE + post.national_id = ? + GROUP BY + post.title, post.initial_price, post.content, post.id, post.service_date, users.username, users.rating + ORDER BY + post.service_date DESC + `; + + connection.query(query, [nationalID], (err, results) => { + if (err) { + console.error('Error executing query:', err); + res.status(500).json({ error: 'An error occurred' }); + } else { + res.json(results); + } + }); + }); + + + // Define the route for retrieving applicants based on post ID +app.get('/applicants/:postId', (req, res) => { + const postId = req.params.postId; + + // Execute the SQL query to fetch applicants + const query = ` + SELECT users.username, users.email, users.rating, users.image, users.national_id, apply.apply_at, apply.accepted_status, apply.apply_price + FROM apply + JOIN users ON users.national_id = apply.national_id + WHERE apply.post_id = ? AND apply.accepted_status != 'R' + `; + + // Execute the query with the post ID as a parameter + connection.query(query, [postId], (error, results) => { + if (error) { + console.error('Error retrieving applicants:', error); + res.status(500).json({ error: 'An error occurred while retrieving applicants.' }); + } else { + // Return the applicants as a JSON response + res.json(results); + } + }); + }); + + + app.post('/updateApplicationStatus', (req, res) => { + const { national_id, post_id, status } = req.body; + const query = ` + UPDATE + apply + SET + accepted_status = ? + WHERE + national_id = ? + AND post_id = ? + `; + + connection.query(query, [status, national_id, post_id], (error) => { + if (error) { + console.error('Error updating application status:', error); + res.sendStatus(500); + } else { + res.sendStatus(200); + } + }); + }); + app.post('/createPost', (req, res) => { + const { national_id, title, location_lat, location_lon, date, time, compensation, description } = req.body; + + // Construct the SQL query + const query = ` + INSERT INTO post (title, content, created_at, national_id, service_date, service_time, location_lat, location_lon, initial_price) + VALUES (?, ?, NOW(), ?, ?, ?, ?, ?, ?) + `; + + // Execute the query + connection.query(query, [title, description, national_id, date, time, location_lat, location_lon, compensation], (error, results) => { + if (error) { + console.error('Error creating post:', error); + res.sendStatus(500); + } else { + res.sendStatus(200); + } + }); + }); + + + app.get('/getApplicationStatus', (req, res) => { + const national_id = req.query.national_id; + const post_id = req.query.post_id; + const query = ` + SELECT accepted_status + FROM apply + WHERE national_id = ? + AND post_id = ? + `; + + connection.query(query, [national_id, post_id], (error, results) => { + if (error) { + console.error('Error retrieving application status:', error); + res.sendStatus(500); + } else { + if (results.length > 0) { + const acceptedStatus = results[0].accepted_status; + res.status(200).json({ acceptedStatus }); + } else { + res.status(404).json({ message: 'Application not found' }); + } + } + }); + }); + +// Retrieve the posts that the user applied to along with the count of non-rejected applications, ordered by service_date +app.get('/appliedPosts/:userId', (req, res) => { + const userId = req.params.userId; + + const query = ` + SELECT post.id, post.title, post.content, post.service_date, post.service_time, post.location_lat, post.location_lon, post.category, post.initial_price, post.state, apply.accepted_status, + COUNT(CASE WHEN apply.accepted_status != 'R' THEN 1 END) AS num_applications + FROM post + INNER JOIN apply ON post.id = apply.post_id + WHERE apply.national_id = ? + GROUP BY post.id + ORDER BY post.service_date ASC + `; + + connection.query(query, [userId], (error, results) => { + if (error) { + console.error('Error retrieving applied posts:', error); + res.status(500).json({ error: 'Failed to retrieve applied posts' }); + } else { + res.json(results); + } + }); +}); + + app.listen(3000, () => console.log('Server started')); diff --git a/app/build.gradle b/app/build.gradle index dad5510..750dadc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ android { defaultConfig { applicationId "com.mariam.registeration" minSdk 26 - targetSdk 33 + targetSdk 34 versionCode 1 versionName "1.0" @@ -41,4 +41,8 @@ dependencies { testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + implementation 'com.google.android.gms:play-services-maps:18.1.0' + implementation 'com.google.android.libraries.places:places:3.2.0' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 916e08b..88bb331 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,94 +2,63 @@ + + + - - - - - - - android:exported="false" /> - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + android:value="AIzaSyAAUKNLUrCJGc3UijGGKO6wz3VIloVlbRU" /> - - \ No newline at end of file + diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png new file mode 100644 index 0000000..273e184 Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ diff --git a/app/src/main/java/com/mariam/registeration/Accepted.java b/app/src/main/java/com/mariam/registeration/Accepted.java new file mode 100644 index 0000000..d836e9b --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/Accepted.java @@ -0,0 +1,31 @@ +package com.mariam.registeration; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +import androidx.appcompat.app.AppCompatActivity; + +public class Accepted extends AppCompatActivity { + private Button viewAppsButton; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_accepted); + + // Find the button in the layout + viewAppsButton = findViewById(R.id.ViewApps); + + // Set click listener for the button + viewAppsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Create an intent to open the target activity + Intent intent = new Intent(Accepted.this, MyRequests.class); + startActivity(intent); + } + }); + } +} diff --git a/app/src/main/java/com/mariam/registeration/Applicants.java b/app/src/main/java/com/mariam/registeration/Applicants.java new file mode 100644 index 0000000..3d3ca8a --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/Applicants.java @@ -0,0 +1,249 @@ +package com.mariam.registeration; + +import androidx.appcompat.app.AppCompatActivity; + +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.TextView; +import android.view.View.OnClickListener; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +class Applicant { + private String natID; + private Double rating; + private String username; + + public Applicant(String natID, Double rating, String username) { + this.natID = natID; + this.rating = rating; + this.username = username; + } + + public String getNatID() { + return natID; + } + + public Double getRating() { + return rating; + } + + public String getUsername() { + return username; + } +} + +public class Applicants extends AppCompatActivity { + + private ListView listView; + private List itemList; + private CustomArrayAdapter adapter; + private ImageButton backButton; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_applicants); + + listView = findViewById(R.id.listView); + itemList = new ArrayList<>(); + + adapter = new CustomArrayAdapter(this, itemList); + listView.setAdapter(adapter); + + int postId = getIntent().getIntExtra("post_id", -1); + Log.e("TAG", "The post id is: " + postId); + + new RetrieveApplicantsTask().execute(postId); + + backButton = findViewById(R.id.backButton); + backButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + goback(); + } + }); + } + + private void goback() { + Intent intent = new Intent(Applicants.this, MyRequests.class); + startActivity(intent); + } + + private class CustomArrayAdapter extends ArrayAdapter { + + public CustomArrayAdapter(Context context, List items) { + super(context, 0, items); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(getContext()).inflate(R.layout.applicants_list_item, parent, false); + } + + Applicant applicant = getItem(position); + + TextView titleText = convertView.findViewById(R.id.titleText); + ImageView icon = convertView.findViewById(R.id.icon); + TextView ratingText = convertView.findViewById(R.id.ratingText); + Button acceptButton = convertView.findViewById(R.id.button1); + Button declineButton = convertView.findViewById(R.id.button2); + + titleText.setText(String.valueOf(applicant.getUsername())); + ratingText.setText(String.valueOf(applicant.getRating())); + + acceptButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + new UpdateApplicationStatusTask().execute(applicant.getNatID(), String.valueOf(getIntent().getIntExtra("post_id", -1)), "A"); + Intent intent = new Intent(Applicants.this, Accepted.class); + startActivity(intent); + } + }); + + declineButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + removeApplicant(position); // Remove the applicant from the list + new UpdateApplicationStatusTask().execute(applicant.getNatID(), String.valueOf(getIntent().getIntExtra("post_id", -1)), "R"); + } + }); + + return convertView; + } + + private void removeApplicant(int position) { + // Remove the applicant from the list + if (position >= 0 && position < getCount()) { + itemList.remove(position); + notifyDataSetChanged(); + } + } + } + + private class RetrieveApplicantsTask extends AsyncTask { + + @Override + protected String doInBackground(Integer... postIds) { + int postId = postIds[0]; + String result = ""; + + try { + URL url = new URL("http://192.168.1.5:3000/applicants/" + postId); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + Log.e("TAG", "URL is "+ url); + + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + StringBuilder stringBuilder = new StringBuilder(); + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + } + reader.close(); + result = stringBuilder.toString(); + } else { + result = "HTTP response code: " + responseCode; + } + + connection.disconnect(); + } catch (Exception e) { + result = e.getMessage(); + } + + return result; + } + + @Override + protected void onPostExecute(String result) { + if (result.startsWith("HTTP response code:")) { + // Handle error + } else { + try { + JSONArray jsonArray = new JSONArray(result); + + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + String natID = jsonObject.getString("national_id"); + Double rating = jsonObject.isNull("rating") ? 0.0 : jsonObject.getDouble("rating"); + String username = jsonObject.getString("username"); + Log.e("TAG","THE JSON IS " + jsonObject); + + Applicant applicant = new Applicant(natID, rating, username); + itemList.add(applicant); + } + + adapter.notifyDataSetChanged(); + } catch (JSONException e) { + Log.e("TAG", "JSONException occurred: " + e.getMessage()); + e.printStackTrace(); + } + } + } + } + + private class UpdateApplicationStatusTask extends AsyncTask { + + @Override + protected Void doInBackground(String... params) { + String natID = params[0]; + String postID = params[1]; + String status = params[2]; + + try { + URL url = new URL("http://192.168.1.5:3000/updateApplicationStatus"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setDoOutput(true); + + JSONObject requestBody = new JSONObject(); + requestBody.put("national_id", natID); + requestBody.put("post_id", postID); + requestBody.put("status", status); + Log.e("TAG", "Testing the request: " + requestBody); + + connection.getOutputStream().write(requestBody.toString().getBytes()); + + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + Log.e("TAG", "it should have worked" + responseCode); + + // Application status updated successfully + } else { + Log.e("TAG", "HTTP response code: " + responseCode); + } + + connection.disconnect(); + } catch (Exception e) { + Log.e("TAG", "Error updating application status: " + e.getMessage()); + } + + return null; + } + } +} + diff --git a/app/src/main/java/com/mariam/registeration/ChangePassword.java b/app/src/main/java/com/mariam/registeration/ChangePassword.java index aa9a788..e2d2c57 100644 --- a/app/src/main/java/com/mariam/registeration/ChangePassword.java +++ b/app/src/main/java/com/mariam/registeration/ChangePassword.java @@ -81,7 +81,7 @@ public void onClick(View v) { } // Make network request to update the password - String apiUrl = "http://10.39.1.162:3000/users/"; // Replace with your API URL + String apiUrl = "http://192.168.1.5:3000/users/"; // Replace with your API URL String username = current_user.getUsername(); // Replace with the username ChangePasswordTask task = new ChangePasswordTask(); task.execute(apiUrl, username, newPassword); diff --git a/app/src/main/java/com/mariam/registeration/CreatePost.java b/app/src/main/java/com/mariam/registeration/CreatePost.java new file mode 100644 index 0000000..76f2bb1 --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/CreatePost.java @@ -0,0 +1,304 @@ +package com.mariam.registeration; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import android.app.DatePickerDialog; +import android.app.TimePickerDialog; +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.TimePicker; +import android.widget.Toast; + +import com.google.android.gms.common.api.Status; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.LatLngBounds; +import com.google.android.libraries.places.api.Places; +import com.google.android.libraries.places.api.model.Place; +import com.google.android.libraries.places.widget.AutocompleteSupportFragment; +import com.google.android.libraries.places.widget.listener.PlaceSelectionListener; + +import org.json.JSONObject; + +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +public class CreatePost extends AppCompatActivity implements DatePickerDialog.OnDateSetListener, TimePickerDialog.OnTimeSetListener { + + private static final String TAG = "CreatePost"; + private static final int AUTOCOMPLETE_REQUEST_CODE = 1; + + private EditText locationEditText; + private EditText dateEditText; + private EditText timeEditText; + private EditText compensationEditText; + private EditText descriptionEditText; + private boolean isPlaceSelected; + private double locationLat; + private double locationLon; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create_post); + + // Check for internet connectivity + if (!isNetworkAvailable()) { + Toast.makeText(this, "No internet connection available", Toast.LENGTH_SHORT).show(); + return; + } + + // Initialize the Places SDK + Places.initialize(getApplicationContext(), "AIzaSyAAUKNLUrCJGc3UijGGKO6wz3VIloVlbRU"); + + // Retrieve the EditText views from the layout + locationEditText = findViewById(R.id.textBox); + dateEditText = findViewById(R.id.dateEditText); + timeEditText = findViewById(R.id.timeEditText); + compensationEditText = findViewById(R.id.compensationTextBox); + descriptionEditText = findViewById(R.id.descriptionTextBox); + + // Initialize the AutocompleteSupportFragment. + AutocompleteSupportFragment autocompleteFragment = (AutocompleteSupportFragment) + getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment); + + // Specify the types of place data to return. + autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.NAME, Place.Field.LAT_LNG)); + + // Set up a PlaceSelectionListener to handle the response. + autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() { + @Override + public void onPlaceSelected(@NonNull Place place) { + Log.i(TAG, "Place: " + place.getName() + ", " + place.getId()); + isPlaceSelected = true; + LatLng latLng = place.getLatLng(); + if (latLng != null) { + locationLat = latLng.latitude; + locationLon = latLng.longitude; + } + } + + @Override + public void onError(@NonNull Status status) { + Log.i(TAG, "An error occurred: " + status); + isPlaceSelected = false; + } + }); + + // Set up the click listener for the Confirm button + Button confirmButton = findViewById(R.id.confirmButton); + confirmButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String location = locationEditText.getText().toString(); + String date = dateEditText.getText().toString(); + String time = timeEditText.getText().toString(); + String compensation = compensationEditText.getText().toString(); + String description = descriptionEditText.getText().toString(); + + if (validateInput(location, date, time, compensation, description)) { + // Format the date to "YYYY-MM-DD" format + String formattedDate = formatDate(date); + + // Proceed with posting the request + new CreatePostTask().execute(location, formattedDate, time, compensation, description); + } else { + Toast.makeText(CreatePost.this, "Please fill in all required fields", Toast.LENGTH_SHORT).show(); + } + } + }); + + // Set up the click listener for the date picker icon + dateEditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showDatePickerDialog(); + } + }); + + // Set up the click listener for the time picker icon + timeEditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showTimePickerDialog(); + } + }); + + View backButton = findViewById(R.id.backButton); + backButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Handle back button press + goback(); + } + }); + } + + private void goback() { + // Start a new activity or perform any other action you desire + Intent intent = new Intent(CreatePost.this, PostService.class); + startActivity(intent); + } + + private void showDatePickerDialog() { + Calendar calendar = Calendar.getInstance(); + int year = calendar.get(Calendar.YEAR); + int month = calendar.get(Calendar.MONTH); + int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); + + DatePickerDialog datePickerDialog = new DatePickerDialog(this, this, year, month, dayOfMonth); + datePickerDialog.show(); + } + + private void showTimePickerDialog() { + Calendar calendar = Calendar.getInstance(); + int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY); + int minute = calendar.get(Calendar.MINUTE); + + TimePickerDialog timePickerDialog = new TimePickerDialog(this, this, hourOfDay, minute, false); + timePickerDialog.show(); + } + + @Override + public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, month); + calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); + String selectedDate = DateFormat.getDateInstance(DateFormat.MEDIUM).format(calendar.getTime()); + dateEditText.setText(selectedDate); + } + + @Override + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + String selectedTime = String.format("%02d:%02d", hourOfDay, minute); + timeEditText.setText(selectedTime); + } + + private boolean isNetworkAvailable() { + // Check network connectivity + return true; // Replace with your actual implementation + } + + private boolean validateInput(String location, String date, String time, String compensation, String description) { + boolean isValid = true; + if (!isPlaceSelected) { + isValid = false; + Toast.makeText(CreatePost.this, "Please select a location", Toast.LENGTH_SHORT).show(); + } + if (location.isEmpty()) { + locationEditText.setError("Location is required"); + isValid = false; + } + + if (date.isEmpty()) { + dateEditText.setError("Date is required"); + isValid = false; + } + + if (time.isEmpty()) { + timeEditText.setError("Time is required"); + isValid = false; + } + + if (compensation.isEmpty()) { + compensationEditText.setError("Compensation is required"); + isValid = false; + } else if (!compensation.matches("\\d+")) { + compensationEditText.setError("Compensation must be a number"); + isValid = false; + } + + if (description.isEmpty()) { + descriptionEditText.setError("Description is required"); + isValid = false; + } + + return isValid; + } + + private String formatDate(String date) { + try { + DateFormat inputDateFormat = new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()); + Date inputDate = inputDateFormat.parse(date); + + DateFormat outputDateFormat = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + return outputDateFormat.format(inputDate); + } catch (ParseException e) { + e.printStackTrace(); + return ""; + } + } + + private class CreatePostTask extends AsyncTask { + + @Override + protected Integer doInBackground(String... params) { + String location = params[0]; + String date = params[1]; + String time = params[2]; + String compensation = params[3]; + String description = params[4]; + + try { + URL url = new URL("http://192.168.1.5:3000/createPost"); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setDoOutput(true); + + JSONObject requestBody = new JSONObject(); + requestBody.put("national_id", "11111111111111"); + requestBody.put("title", location); + requestBody.put("location_lat", locationLat); + requestBody.put("location_lon", locationLon); + requestBody.put("date", date); + requestBody.put("time", time); + requestBody.put("compensation", compensation); + requestBody.put("description", description); + + OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream()); + writer.write(requestBody.toString()); + writer.flush(); + + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + return responseCode; + } else { + return -1; // Request failed + } + } catch (Exception e) { + Log.e(TAG, "Error creating post: " + e.getMessage()); + return -1; // Request failed + } + } + + @Override + protected void onPostExecute(Integer responseCode) { + if (responseCode == HttpURLConnection.HTTP_OK) { + // Post created successfully + Toast.makeText(CreatePost.this, "Post created successfully", Toast.LENGTH_SHORT).show(); + Intent intent = new Intent(CreatePost.this, PostConfirmation.class); + startActivity(intent); + } else { + // Handle error + Toast.makeText(CreatePost.this, "Failed to create post", Toast.LENGTH_SHORT).show(); + } + } + } +} diff --git a/app/src/main/java/com/mariam/registeration/HomeActivity.java b/app/src/main/java/com/mariam/registeration/HomeActivity.java index 52850aa..fc776c8 100644 --- a/app/src/main/java/com/mariam/registeration/HomeActivity.java +++ b/app/src/main/java/com/mariam/registeration/HomeActivity.java @@ -1,36 +1,18 @@ package com.mariam.registeration; -import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; import android.content.Intent; -import android.content.pm.PackageManager; -import android.location.Address; -import android.location.Geocoder; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.media.Image; import android.os.AsyncTask; import android.os.Bundle; -import android.text.BoringLayout; import android.util.Log; -import android.util.Pair; import android.view.View; import android.widget.AdapterView; import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.ProgressBar; import android.widget.TextView; -import android.widget.Toast; - -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; -import com.google.android.gms.location.FusedLocationProviderClient; -import com.google.android.gms.location.LocationServices; -import com.google.android.gms.tasks.OnSuccessListener; import com.mariam.registeration.R.drawable; import com.mariam.registeration.R.id; import com.mariam.registeration.R.layout; @@ -38,61 +20,30 @@ import org.json.JSONArray; import org.json.JSONObject; -import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; -import java.time.Duration; -import java.time.LocalDate; -import java.time.Period; import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -public class HomeActivity extends AppCompatActivity{ +public class HomeActivity extends AppCompatActivity { TextView filterBtn; ArrayList reqs; - FusedLocationProviderClient fusedLocationProviderClient; - double lat, lon; - private final static int REQUEST_CODE = 100; - - + private static final int REQUEST_CODE = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_home); -// int[] images = new int[]{R.drawable.a, R.drawable.a, R.drawable.a, R.drawable.a, R.drawable.a}; -// String[] descs = new String[]{"Walk my dog for 20 minutes hjklh hjkl hlk; hl;kjkl; kl; hjkl;hhiohiopph upu huioguiogo guio guiog uio ij kl hjlh oih uj lhuiohhuiohuioghuio hio huioh uiohuioh uiohu iohuiohui", "Change 4 light bulbs", "Change 4 light bulbs", "Mow my loan", "Deliver a 4kg package"}; -// String[] titles = new String[]{"Pet Care", "Installation", "Installation", "Gardening", "Transportation"}; -// String[] dates = new String[]{"2023-07-11", "2023-07-10", "2023-07-05", "2023-06-11", "2023-07-09",}; -// -// //30.023008, 31.518187 30.034054, 31.450164 30.071717365740923, 31.369465196372992 30.08602403142341, 31.27112588129936 30.05438645981498, 31.00419195220193 -// double[] locationLat = new double[]{30.023008, 30.034054, 30.071717365740923, 30.08602403142341, 30.05438645981498}; -// double[] locationLon = new double[]{31.518187, 31.450164, 31.369465196372992, 31.27112588129936, 31.00419195220193}; -// int[] prices = new int[]{100, 200, 300, 100, 200}; - - - - - -// for (int i = 0; i < 5; ++i) { -// Request req = new Request(titles[i], descs[i], dates[i], locationLat[i], locationLon[i], 2.0F, prices[i], R.drawable.a); -// reqs.add(req); -// } + reqs = new ArrayList<>(); - //current Location - - reqs = new ArrayList(); getAllRequests getReqs = new getAllRequests(); ActivityCompat.requestPermissions(HomeActivity.this, new String[]{android.Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE); location loc = new location(); - loc.setCtx(this); loc.getLastLocation(); Request req = new Request(); @@ -101,8 +52,6 @@ protected void onCreate(Bundle savedInstanceState) { getReqs.execute(); - - Intent intent = getIntent(); User current_user = (User) intent.getSerializableExtra("current_user"); TextView profile_button = findViewById(R.id.navProfile); @@ -114,31 +63,27 @@ public void onClick(View v) { startActivity(intent); } }); - } - - -// -// for (Request req : reqs) { -// req.setCurrentLocations(address.get(0).getLatitude(), address.get(0).getLongitude()); - - - + // Set click listener for navPost + TextView navPost = findViewById(R.id.navPost); + navPost.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Redirect to another page + Intent intent = new Intent(HomeActivity.this, MyRequests.class); + startActivity(intent); + } + }); + } public class getAllRequests extends AsyncTask { - private static final String API_URL = "http://"+"192.168.1.8:3000/"+"posts"; + private static final String API_URL = "http://192.168.1.5:3000/posts"; public static final String REQUEST_METHOD = "GET"; public static final int READ_TIMEOUT = 15000; public static final int CONNECTION_TIMEOUT = 15000; - - @Override - protected void onPreExecute() { - } - @Override protected String doInBackground(String... strings) { - HttpURLConnection urlConnection = null; BufferedReader reader = null; StringBuilder stringBuilder = new StringBuilder(); @@ -171,9 +116,7 @@ protected String doInBackground(String... strings) { } return stringBuilder.toString(); - - - } + } @Override protected void onPostExecute(String s) { @@ -181,7 +124,7 @@ protected void onPostExecute(String s) { Log.i("NETTTTT", s); JSONArray jsonarr = new JSONArray(s); int arrSize = jsonarr.length(); - for(int i =0; i maxdis || reqs.get(i).distance() < mindis) { - reqs.remove(i); - i--; - } - + reqs.remove(i); + i--; + } } for (int i = 0; i < reqs.size(); i++) { @@ -306,11 +211,8 @@ protected void display(){ i--; } } - - } - RequestAdaptor adaptor = new RequestAdaptor(HomeActivity.this, reqs); ListView lv = (ListView) HomeActivity.this.findViewById(id.listView); HomeActivity.this.filterBtn = (TextView) HomeActivity.this.findViewById(id.filterButton); @@ -341,8 +243,6 @@ public void onClick(View view) { HomeActivity.this.startActivity(intent); } }); - } } } - diff --git a/app/src/main/java/com/mariam/registeration/Login.java b/app/src/main/java/com/mariam/registeration/Login.java index d03260a..466dceb 100644 --- a/app/src/main/java/com/mariam/registeration/Login.java +++ b/app/src/main/java/com/mariam/registeration/Login.java @@ -89,7 +89,7 @@ public void onClick(View v) { } else if (TextUtils.isEmpty(password)) { mPasswordEditText.setError("Please enter your password"); } else { - final String API_URL = "http://192.168.1.8:3000/login"; + final String API_URL = "http://192.168.1.5:3000/login"; new Thread(new Runnable() { @Override public void run() { diff --git a/app/src/main/java/com/mariam/registeration/MainActivity.java b/app/src/main/java/com/mariam/registeration/MainActivity.java index 37eb112..801f746 100644 --- a/app/src/main/java/com/mariam/registeration/MainActivity.java +++ b/app/src/main/java/com/mariam/registeration/MainActivity.java @@ -11,7 +11,7 @@ import org.w3c.dom.Text; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ -//login or signup + //login or signup private Button Signup; private TextView Login; @Override diff --git a/app/src/main/java/com/mariam/registeration/MyApplications.java b/app/src/main/java/com/mariam/registeration/MyApplications.java new file mode 100644 index 0000000..bc08ae9 --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/MyApplications.java @@ -0,0 +1,273 @@ +package com.mariam.registeration; + +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityOptionsCompat; + +import com.google.android.material.tabs.TabLayout; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +public class MyApplications extends AppCompatActivity { + private TabLayout tabLayout; + private ListView listView; + private AppAdapter adapter; + private String userId = "11111111111111"; // Replace with the actual user ID + + // App class declaration + public class App { + private String title; + private String content; + private int iconResId; + private int rejectedIconResId; + private String date; + private int numOfApplications; + private int price; + + public App(String title, String content, int iconResId, int rejectedIconResId, String date, int numOfApplications, int price) { + this.title = title; + this.content = content; + this.iconResId = iconResId; + this.rejectedIconResId = rejectedIconResId; + this.date = date; + this.numOfApplications = numOfApplications; + this.price = price; + } + + public String getTitle() { + return title; + } + + public String getContent() { + return content; + } + + public int getIconResId() { + return iconResId; + } + + public int getRejectedIconResId() { + return rejectedIconResId; + } + + public String getDate() { + return date; + } + + public int getNumOfApplications() { + return numOfApplications; + } + + public int getPrice() { + return price; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_applications); + + // Find the TabLayout by its ID + tabLayout = findViewById(R.id.tabLayout); + + tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + int position = tab.getPosition(); + + if (position == 0) { + // My Requests tab selected + Intent intent = new Intent(MyApplications.this, MyRequests.class); + + // Apply custom transition animations + ActivityOptionsCompat options = ActivityOptionsCompat.makeCustomAnimation(MyApplications.this, + android.R.anim.fade_in, android.R.anim.fade_out); + startActivity(intent, options.toBundle()); + } + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + // Do nothing + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + // Do nothing + } + }); + + TabLayout.Tab myApplicationsTab = tabLayout.getTabAt(1); + if (myApplicationsTab != null) { + myApplicationsTab.select(); + } + + // Initialize the ListView + listView = findViewById(R.id.listView); + + // Create and set the adapter + adapter = new AppAdapter(this, new ArrayList<>()); + listView.setAdapter(adapter); + + // Retrieve the applied posts + RetrieveAppliedPostsTask task = new RetrieveAppliedPostsTask(); + task.execute(); + } + + private class AppAdapter extends ArrayAdapter { + private LayoutInflater inflater; + + public AppAdapter(Context context, List apps) { + super(context, 0, apps); + inflater = LayoutInflater.from(context); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + ViewHolder viewHolder; + + if (view == null) { + view = inflater.inflate(R.layout.apps_list_item, parent, false); + viewHolder = new ViewHolder(); + viewHolder.iconImageView = view.findViewById(R.id.userImage); + viewHolder.titleTextView = view.findViewById(R.id.title); + viewHolder.descTextView = view.findViewById(R.id.desc); + viewHolder.dateTextView = view.findViewById(R.id.date); + viewHolder.numOfApplicationsTextView = view.findViewById(R.id.numofapplications); + viewHolder.priceTextView = view.findViewById(R.id.price); + viewHolder.rejectedIconImageView = view.findViewById(R.id.rejectedIcon); + view.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) view.getTag(); + } + + App app = getItem(position); + + if (app != null) { + viewHolder.iconImageView.setImageResource(app.getIconResId()); + viewHolder.titleTextView.setText(app.getTitle()); + viewHolder.descTextView.setText(app.getContent()); + viewHolder.dateTextView.setText(app.getDate()); + viewHolder.numOfApplicationsTextView.setText(String.valueOf(app.getNumOfApplications()) +" Apps"); + viewHolder.priceTextView.setText(String.valueOf(app.getPrice()) +" EGP"); + + + // Set rejectedIcon visibility based on the rejectedIconResId + if (app.getRejectedIconResId() != 0) { + viewHolder.rejectedIconImageView.setVisibility(View.VISIBLE); + viewHolder.rejectedIconImageView.setImageResource(app.getRejectedIconResId()); + } else { + viewHolder.rejectedIconImageView.setVisibility(View.GONE); + } + } + + return view; + } + + private class ViewHolder { + ImageView iconImageView; + TextView titleTextView; + TextView descTextView; + TextView dateTextView; + TextView numOfApplicationsTextView; + TextView priceTextView; + ImageView rejectedIconImageView; + } + } + + private class RetrieveAppliedPostsTask extends AsyncTask { + + @Override + protected String doInBackground(Void... voids) { + String result = ""; + + try { + URL url = new URL("http://192.168.1.5:3000/appliedPosts/" + userId); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + StringBuilder stringBuilder = new StringBuilder(); + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + } + reader.close(); + result = stringBuilder.toString(); + } else { + result = "HTTP response code: " + responseCode; + } + + connection.disconnect(); + } catch (Exception e) { + Log.e("TAG", "Error retrieving applied posts", e); + result = e.getMessage(); + } + + return result; + } + + @Override + protected void onPostExecute(String result) { + // Process the retrieved data and update the adapter + try { + JSONArray postsArray = new JSONArray(result); + List appsList = new ArrayList<>(); + + for (int i = 0; i < postsArray.length(); i++) { + JSONObject postObject = postsArray.getJSONObject(i); + String title = postObject.getString("title"); + String content = postObject.getString("content"); + String acceptedStatus = postObject.getString("accepted_status"); + String rawServiceDate = postObject.getString("service_date"); + String date = rawServiceDate.split("T")[0]; + int numOfApplications = postObject.getInt("num_applications"); + int price = postObject.getInt("initial_price"); + + // Determine the rejectedIconResId based on the acceptedStatus + int rejectedIconResId = 0; + if (acceptedStatus.equals("R")) { + rejectedIconResId = R.drawable.rejected; + } else if (acceptedStatus.equals("P")) { + rejectedIconResId = R.drawable.pending; + } else if (acceptedStatus.equals("A")) { + rejectedIconResId = R.drawable.accepted; + } + + // Create a new App object and add it to the list + appsList.add(new App(title, content, R.drawable.person, rejectedIconResId, date, numOfApplications, price)); + } + + // Clear the adapter and add the retrieved apps to it + adapter.clear(); + adapter.addAll(appsList); + } catch (JSONException e) { + e.printStackTrace(); + } + } + } +} diff --git a/app/src/main/java/com/mariam/registeration/MyRequests.java b/app/src/main/java/com/mariam/registeration/MyRequests.java new file mode 100644 index 0000000..b9cec0a --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/MyRequests.java @@ -0,0 +1,305 @@ +package com.mariam.registeration; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityOptionsCompat; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.android.material.tabs.TabLayout; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +class CustomItem { + private String title; + private String description; + private int price; + private String date; + private int numApplications; + private int postId; + private boolean hasAcceptedApplicant; + + public CustomItem(String title, String description, int price, String date, int numApplications, int postId, boolean hasAcceptedApplicant) { + this.title = title; + this.description = description; + this.price = price; + this.date = date; + this.numApplications = numApplications; + this.postId = postId; + this.hasAcceptedApplicant = hasAcceptedApplicant; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public int getPrice() { + return price; + } + + public String getDate() { + return date; + } + + public int getNumApplications() { + return numApplications; + } + + public boolean hasAcceptedApplicant() { + return hasAcceptedApplicant; + } + + @Override + public String toString() { + return title; // or any other desired format + } + + public int getPostId() { + return postId; + } +} + +public class MyRequests extends AppCompatActivity { + + private ListView listView; + private List itemList; + private CustomArrayAdapter adapter; + private TabLayout tabLayout; + private FloatingActionButton fabCreatePost; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_requests); + + listView = findViewById(R.id.listView); + tabLayout = findViewById(R.id.tabLayout); + + // Initialize the itemList + itemList = new ArrayList<>(); + + // Set the adapter with the custom ArrayAdapter + adapter = new CustomArrayAdapter(this, itemList); + listView.setAdapter(adapter); + + fabCreatePost = findViewById(R.id.fabCreatePost); + + // Set a click listener for the FloatingActionButton + fabCreatePost.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(MyRequests.this, PostService.class); + startActivity(intent); + } + }); + + ImageView icon1 = findViewById(R.id.icon1); + ImageView icon3 = findViewById(R.id.icon3); + + + icon1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Handle icon1 click here + Intent intent = new Intent(MyRequests.this, HomeActivity.class); + startActivity(intent); + } + }); + + icon3.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Handle icon1 click here + Intent intent = new Intent(MyRequests.this, ProfileMain.class); + startActivity(intent); + } + }); + + tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + int position = tab.getPosition(); + + if (position == 1) { + // My Applications tab selected + Intent intent = new Intent(MyRequests.this, MyApplications.class); + + // Apply custom transition animations + ActivityOptionsCompat options = ActivityOptionsCompat.makeCustomAnimation(MyRequests.this, + android.R.anim.fade_in, android.R.anim.fade_out); + startActivity(intent, options.toBundle()); + } + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + // Do nothing + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + // Do nothing + } + }); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + // Get the selected item + CustomItem selectedItem = itemList.get(position); + + if (selectedItem.hasAcceptedApplicant()) { + // Redirect to the Accepted page + Intent intent = new Intent(MyRequests.this, Accepted.class); + intent.putExtra("post_id", selectedItem.getPostId()); + startActivity(intent); + } else { + // Open the Applicants activity and pass the post ID + Intent intent = new Intent(MyRequests.this, Applicants.class); + intent.putExtra("post_id", selectedItem.getPostId()); + startActivity(intent); + } + } + }); + + // Make the HTTP request to retrieve the combined data with accepted status + new RetrieveCombinedDataWithAcceptedTask().execute(); + } + + private class CustomArrayAdapter extends ArrayAdapter { + + public CustomArrayAdapter(Context context, List items) { + super(context, 0, items); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = LayoutInflater.from(getContext()).inflate(R.layout.requests_list_item, parent, false); + } + + CustomItem item = getItem(position); + + TextView titleText = convertView.findViewById(R.id.titleText); + TextView descriptionText = convertView.findViewById(R.id.descriptionText); + TextView priceText = convertView.findViewById(R.id.price); + TextView dateText = convertView.findViewById(R.id.date); + TextView applicationsText = convertView.findViewById(R.id.numofapplications); + + // Set the values for the TextView elements + titleText.setText(item.getTitle()); + descriptionText.setText(item.getDescription()); + priceText.setText(String.valueOf(item.getPrice()) + " EGP"); + dateText.setText(item.getDate()); + applicationsText.setText(item.getNumApplications() + " Apps"); + + return convertView; + } + } + + private class RetrieveCombinedDataWithAcceptedTask extends AsyncTask { + + @Override + protected String doInBackground(Void... voids) { + String result = ""; + + try { + //String nationalID = getNationalIDFromSharedPreferences(); // Retrieve the national ID + String nationalID = "11111111111111"; // Retrieve the national ID + + URL url = new URL("http://192.168.1.5:3000/combinedData/" + nationalID); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + Log.e("TAG", "connection is " + connection); + + int responseCode = connection.getResponseCode(); + if (responseCode == HttpURLConnection.HTTP_OK) { + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + StringBuilder stringBuilder = new StringBuilder(); + while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + } + reader.close(); + result = stringBuilder.toString(); + } else { + result = "HTTP response code: " + responseCode; + } + + connection.disconnect(); + } catch (Exception e) { + Log.e("TAG", "Error retrieving combined data with accepted status", e); + result = e.getMessage(); + } + + return result; + } + + @Override + protected void onPostExecute(String result) { + if (result.startsWith("HTTP response code:")) { + // Handle error + Log.e("TAG", result); + } else { + // Parse the JSON response + try { + JSONArray jsonArray = new JSONArray(result); + Log.d("TAG", "JSON response: " + result); + + for (int i = 0; i < jsonArray.length(); i++) { + JSONObject jsonObject = jsonArray.getJSONObject(i); + String title = jsonObject.getString("title"); + int initialPrice = jsonObject.getInt("initial_price"); + String username = jsonObject.getString("username"); + String itemDescription = jsonObject.getString("content"); + String rawServiceDate = jsonObject.getString("service_date"); + String serviceDate = rawServiceDate.split("T")[0]; + int numApplications = jsonObject.getInt("num_applications"); + int postId = jsonObject.getInt("id"); + int intValue = jsonObject.getInt("has_accepted_applicant"); + boolean hasAccepted = (intValue != 0); + + CustomItem item = new CustomItem(title, itemDescription, initialPrice, serviceDate, numApplications, postId, hasAccepted); + itemList.add(item); + } + adapter.notifyDataSetChanged(); + + Log.d("TAG", "Parsed JSON response. Item count: " + itemList.size()); + } catch (JSONException e) { + Log.e("TAG", "Error parsing JSON response", e); + } + } + } + } + + private String getNationalIDFromSharedPreferences() { + SharedPreferences preferences = getSharedPreferences("MyPrefs", MODE_PRIVATE); + return preferences.getString("Nat_ID", ""); + } +} diff --git a/app/src/main/java/com/mariam/registeration/NavigationActivity.java b/app/src/main/java/com/mariam/registeration/NavigationActivity.java new file mode 100644 index 0000000..57bc7d2 --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/NavigationActivity.java @@ -0,0 +1,12 @@ +package com.mariam.registeration; +import androidx.appcompat.app.AppCompatActivity; +import android.os.Bundle; + +public class NavigationActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + } +} diff --git a/app/src/main/java/com/mariam/registeration/PostConfirmation.java b/app/src/main/java/com/mariam/registeration/PostConfirmation.java new file mode 100644 index 0000000..df78e48 --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/PostConfirmation.java @@ -0,0 +1,31 @@ +package com.mariam.registeration; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; + +import androidx.appcompat.app.AppCompatActivity; + +public class PostConfirmation extends AppCompatActivity { + private Button viewAppsButton; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_post_confirmation); + + // Find the button in the layout + viewAppsButton = findViewById(R.id.ViewApps); + + // Set click listener for the button + viewAppsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Create an intent to open the target activity + Intent intent = new Intent(PostConfirmation.this, MyRequests.class); + startActivity(intent); + } + }); + } +} diff --git a/app/src/main/java/com/mariam/registeration/PostService.java b/app/src/main/java/com/mariam/registeration/PostService.java new file mode 100644 index 0000000..84ed048 --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/PostService.java @@ -0,0 +1,135 @@ +package com.mariam.registeration; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import androidx.appcompat.app.AppCompatActivity; + +import java.util.ArrayList; +import java.util.List; + +class Services { + private String title; + private String description; + private int icon; + + public Services(String title, String description, int icon) { + this.title = title; + this.description = description; + this.icon = icon; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public int getIcon() { + return icon; + } +} + +public class PostService extends AppCompatActivity { + private ImageButton backButton; + private ListView listView; + private List itemList; + private ArrayAdapter adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_post_service); + + listView = findViewById(R.id.listView); + + // Initialize the itemList + itemList = new ArrayList<>(); + + itemList.add(new Services("Pet Care", "Seeking help with pet sitting, dog walking, or pet grooming.", R.drawable.pets)); + itemList.add(new Services("Installation", "Pertaining any furniture installation or basic handyman tasks around the house.", R.drawable.installation)); + itemList.add(new Services("Gardening", "Help with your home garden: mowing the lawn, trimming bushes, washing pavement, etc...", R.drawable.garden)); + itemList.add(new Services("Transportation", "Whether you want to carpool, deliver an item, or pick up something.", R.drawable.transportation)); + itemList.add(new Services("Car Care", "Need someone to wash your car, fill up the gas tank, or anything car related.", R.drawable.car)); + + adapter = new ArrayAdapter(this, R.layout.service_list_item, R.id.titleText, itemList) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = super.getView(position, convertView, parent); + ViewHolder viewHolder; + + if (convertView == null) { + viewHolder = new ViewHolder(); + viewHolder.iconImageView = view.findViewById(R.id.icon); + viewHolder.titleTextView = view.findViewById(R.id.titleText); + viewHolder.descriptionTextView = view.findViewById(R.id.descriptionText); + view.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) view.getTag(); + } + + Services service = getItem(position); + + if (service != null) { + viewHolder.iconImageView.setImageResource(service.getIcon()); + viewHolder.titleTextView.setText(service.getTitle()); + viewHolder.descriptionTextView.setText(service.getDescription()); + } + + return view; + } + }; + + listView.setAdapter(adapter); + + // Handle item click event + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Services service = itemList.get(position); + if (service != null) { + String selectedTitle = service.getTitle(); + moveToNextActivity(selectedTitle); + } + } + }); + + backButton = findViewById(R.id.backButton); + backButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // Handle back button press + goback(); + } + }); + } + + private void moveToNextActivity(String selectedTitle) { + // Start a new activity or perform any other action you desire + Intent intent = new Intent(PostService.this, CreatePost.class); + intent.putExtra("title", selectedTitle); + startActivity(intent); + } + + private void goback() { + // Start a new activity or perform any other action you desire + Intent intent = new Intent(PostService.this, MyRequests.class); + startActivity(intent); + } + + private class ViewHolder { + ImageView iconImageView; + TextView titleTextView; + TextView descriptionTextView; + } +} diff --git a/app/src/main/java/com/mariam/registeration/ProfileMain.java b/app/src/main/java/com/mariam/registeration/ProfileMain.java index 612b6bd..ac1fd26 100644 --- a/app/src/main/java/com/mariam/registeration/ProfileMain.java +++ b/app/src/main/java/com/mariam/registeration/ProfileMain.java @@ -285,7 +285,7 @@ private class UpdateDescriptionTask extends AsyncTask { protected String doInBackground(String... params) { String username = params[0]; String rawDescription = params[1]; - String apiUrl = "http://10.39.1.162:3000/users/" + username + "/description"; + String apiUrl = "http://192.168.1.5:3000/users/" + username + "/description"; try { URL url = new URL(apiUrl); @@ -340,7 +340,7 @@ private class GetUserDetailsTask extends AsyncTask { @Override protected String doInBackground(String... params) { String nationalId = params[0]; - String apiUrl = "http://10.39.1.162:3000/users/" + nationalId + "/details"; + String apiUrl = "http://192.168.1.5:3000/users/" + nationalId + "/details"; try { URL url = new URL(apiUrl); diff --git a/app/src/main/java/com/mariam/registeration/Requests.java b/app/src/main/java/com/mariam/registeration/Requests.java new file mode 100644 index 0000000..0952d9b --- /dev/null +++ b/app/src/main/java/com/mariam/registeration/Requests.java @@ -0,0 +1,81 @@ +package com.mariam.registeration; + +import android.content.ClipData; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import androidx.appcompat.app.AppCompatActivity; + +import com.google.android.material.tabs.TabLayout; + +import java.util.ArrayList; +import java.util.List; + +public class Requests extends AppCompatActivity { + private ListView listView; + private List itemList; + private ArrayAdapter adapter; + private TabLayout tabLayout; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_requests); + + listView = findViewById(R.id.listView); + tabLayout = findViewById(R.id.tabLayout); + + // Generate random data + generateRandomData(); + + // Create adapter + adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, itemList); + + // Set adapter to ListView + listView.setAdapter(adapter); + + // Set tab layout onTabSelected listener + tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + int position = tab.getPosition(); + + if (position == 0) { + // My Requests tab selected + Intent intent = new Intent(Requests.this, Requests.class); + startActivity(intent); + } else if (position == 1) { + // My Applications tab selected + Intent intent = new Intent(Requests.this, MyApplications.class); + startActivity(intent); + } + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + // Do nothing + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + // Do nothing + } + }); + } + + private void generateRandomData() { + itemList = new ArrayList<>(); + + // Generate 10 random items + for (int i = 0; i < 10; i++) { + String name = "Item " + (i + 1); + String description = "Description " + (i + 1); + ClipData.Item item = new ClipData.Item(name, description); + itemList.add(item); + } + } +} diff --git a/app/src/main/java/com/mariam/registeration/register_done.java b/app/src/main/java/com/mariam/registeration/register_done.java index 4a95152..55641d6 100644 --- a/app/src/main/java/com/mariam/registeration/register_done.java +++ b/app/src/main/java/com/mariam/registeration/register_done.java @@ -61,7 +61,7 @@ public void onClick(View view) { editor.putString("description", user.getDescription()); editor.apply(); Log.i("done","done"); - final String API_URL = "http://192.168.1.8:3000/adduser"; + final String API_URL = "http://192.168.1.5:3000/adduser"; new Thread(new Runnable() { @Override public void run() { diff --git a/app/src/main/res/drawable/accepted.png b/app/src/main/res/drawable/accepted.png new file mode 100644 index 0000000..21289a3 Binary files /dev/null and b/app/src/main/res/drawable/accepted.png differ diff --git a/app/src/main/res/drawable/addcircle.xml b/app/src/main/res/drawable/addcircle.xml new file mode 100644 index 0000000..0f1e647 --- /dev/null +++ b/app/src/main/res/drawable/addcircle.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/backbtn.xml b/app/src/main/res/drawable/backbtn.xml new file mode 100644 index 0000000..27bc856 --- /dev/null +++ b/app/src/main/res/drawable/backbtn.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/button_style1.xml b/app/src/main/res/drawable/button_style1.xml index cd3a196..1e15fc1 100644 --- a/app/src/main/res/drawable/button_style1.xml +++ b/app/src/main/res/drawable/button_style1.xml @@ -1,4 +1,5 @@ + diff --git a/app/src/main/res/drawable/calendar.xml b/app/src/main/res/drawable/calendar.xml new file mode 100644 index 0000000..15efc5f --- /dev/null +++ b/app/src/main/res/drawable/calendar.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/car.xml b/app/src/main/res/drawable/car.xml new file mode 100644 index 0000000..87a4fef --- /dev/null +++ b/app/src/main/res/drawable/car.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/done_outline_48px.xml b/app/src/main/res/drawable/done_outline_48px.xml index c58dde5..f27743a 100644 --- a/app/src/main/res/drawable/done_outline_48px.xml +++ b/app/src/main/res/drawable/done_outline_48px.xml @@ -3,7 +3,7 @@ android:height="48dp" android:viewportWidth="960" android:viewportHeight="960" - android:tint="@color/darkBlue"> + android:tint="#2D4059"> diff --git a/app/src/main/res/drawable/event.xml b/app/src/main/res/drawable/event.xml new file mode 100644 index 0000000..15efc5f --- /dev/null +++ b/app/src/main/res/drawable/event.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/garden.xml b/app/src/main/res/drawable/garden.xml new file mode 100644 index 0000000..7e00e90 --- /dev/null +++ b/app/src/main/res/drawable/garden.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/homebtn.xml b/app/src/main/res/drawable/homebtn.xml new file mode 100644 index 0000000..baa758b --- /dev/null +++ b/app/src/main/res/drawable/homebtn.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 07d5da9..ca3826a 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,170 +1,74 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + xmlns:android="http://schemas.android.com/apk/res/android"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/installation.xml b/app/src/main/res/drawable/installation.xml new file mode 100644 index 0000000..ab7b08e --- /dev/null +++ b/app/src/main/res/drawable/installation.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/listicon.xml b/app/src/main/res/drawable/listicon.xml new file mode 100644 index 0000000..e0c021d --- /dev/null +++ b/app/src/main/res/drawable/listicon.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable/location.xml b/app/src/main/res/drawable/location.xml new file mode 100644 index 0000000..8816ce2 --- /dev/null +++ b/app/src/main/res/drawable/location.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/paragraph.xml b/app/src/main/res/drawable/paragraph.xml new file mode 100644 index 0000000..383a3e4 --- /dev/null +++ b/app/src/main/res/drawable/paragraph.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/payments.xml b/app/src/main/res/drawable/payments.xml new file mode 100644 index 0000000..165b152 --- /dev/null +++ b/app/src/main/res/drawable/payments.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/pencil.xml b/app/src/main/res/drawable/pencil.xml new file mode 100644 index 0000000..080e00a --- /dev/null +++ b/app/src/main/res/drawable/pencil.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/pending.png b/app/src/main/res/drawable/pending.png new file mode 100644 index 0000000..728f090 Binary files /dev/null and b/app/src/main/res/drawable/pending.png differ diff --git a/app/src/main/res/drawable/person.jpg b/app/src/main/res/drawable/person.jpg new file mode 100644 index 0000000..f2e9f1b Binary files /dev/null and b/app/src/main/res/drawable/person.jpg differ diff --git a/app/src/main/res/drawable/pets.xml b/app/src/main/res/drawable/pets.xml new file mode 100644 index 0000000..c1b6108 --- /dev/null +++ b/app/src/main/res/drawable/pets.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/profilebtn.xml b/app/src/main/res/drawable/profilebtn.xml new file mode 100644 index 0000000..99563ac --- /dev/null +++ b/app/src/main/res/drawable/profilebtn.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/rejected.png b/app/src/main/res/drawable/rejected.png new file mode 100644 index 0000000..c835a28 Binary files /dev/null and b/app/src/main/res/drawable/rejected.png differ diff --git a/app/src/main/res/drawable/requestsbtn.xml b/app/src/main/res/drawable/requestsbtn.xml new file mode 100644 index 0000000..7e80954 --- /dev/null +++ b/app/src/main/res/drawable/requestsbtn.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/rightarrow.xml b/app/src/main/res/drawable/rightarrow.xml new file mode 100644 index 0000000..b7fbf98 --- /dev/null +++ b/app/src/main/res/drawable/rightarrow.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/rounded_background.xml b/app/src/main/res/drawable/rounded_background.xml new file mode 100644 index 0000000..65b4a97 --- /dev/null +++ b/app/src/main/res/drawable/rounded_background.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/rounded_corner_all.xml b/app/src/main/res/drawable/rounded_corner_all.xml index c5d4a80..ad691b1 100644 --- a/app/src/main/res/drawable/rounded_corner_all.xml +++ b/app/src/main/res/drawable/rounded_corner_all.xml @@ -1,9 +1,7 @@ - - + android:color="#DBE2EF"/> + + + diff --git a/app/src/main/res/drawable/rounded_text_background.xml b/app/src/main/res/drawable/rounded_text_background.xml new file mode 100644 index 0000000..b184049 --- /dev/null +++ b/app/src/main/res/drawable/rounded_text_background.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/drawable/star.xml b/app/src/main/res/drawable/star.xml new file mode 100644 index 0000000..43764c0 --- /dev/null +++ b/app/src/main/res/drawable/star.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/transportation.xml b/app/src/main/res/drawable/transportation.xml new file mode 100644 index 0000000..4d9bd66 --- /dev/null +++ b/app/src/main/res/drawable/transportation.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_accepted.xml b/app/src/main/res/layout/activity_accepted.xml new file mode 100644 index 0000000..62f4968 --- /dev/null +++ b/app/src/main/res/layout/activity_accepted.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + +