Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ android {
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.mobilelab"
minSdkVersion 21
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
Expand All @@ -22,6 +23,18 @@ android {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
packagingOptions {
exclude 'project.properties'
exclude 'META-INF/INDEX.LIST'
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}
}

dependencies {
Expand All @@ -33,6 +46,7 @@ dependencies {
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.firebase:firebase-auth:19.1.0'
implementation 'com.google.firebase:firebase-auth:19.2.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.google.cloud:google-cloud-storage:1.101.0'
}
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
</activity>
<activity android:name=".SignUpActivity" />
<activity android:name=".ItemDetailsActivity" />
<activity android:name=".NewItemActivity" />
</application>

</manifest>
19 changes: 18 additions & 1 deletion app/src/main/java/com/example/mobilelab/Good.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import com.google.gson.annotations.SerializedName;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;

public class Good {

Expand All @@ -28,6 +30,21 @@ public Good(String title, String place, float price, String img, long date) {
this.date = date;
}

public Good(String title, String place, String date, String price, String img) {
this.title = title;
this.place = place;
this.price = Float.parseFloat(price);
this.img = img;
final String pattern = "dd/MM/yyyy";
SimpleDateFormat format = new SimpleDateFormat(pattern, Locale.US);
try {
Date parsedDate = format.parse(date);
this.date = Objects.requireNonNull(parsedDate).getTime();
} catch (ParseException e) {
e.printStackTrace();
}
}

public String getTitle() {
return title;
}
Expand All @@ -41,7 +58,7 @@ public String getPrice() {
}

public String getImg() {
return String.format("%s%s", "http://bowling-iot.pp.ua", img);
return img;
}

public String getDate() {
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/com/example/mobilelab/GoodsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
import java.util.List;

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;

public interface GoodsService {
@GET("goods/all")
Call<List<Good>> listGoods();

@POST("goods_android/")
Call<Good> addGood(@Body Good good);
}
4 changes: 4 additions & 0 deletions app/src/main/java/com/example/mobilelab/ListFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.LayoutInflater;
Expand Down Expand Up @@ -57,6 +58,9 @@ private void initFields(final View view) {
DividerItemDecoration itemDecor = new DividerItemDecoration(Objects.requireNonNull(getActivity()), VERTICAL);
recyclerView.addItemDecoration(itemDecor);
recyclerView.setAdapter(new GoodsAdapter(main.getContext(), new ArrayList<>(), R.layout.list_item_good));
view.findViewById(R.id.new_item_button).setOnClickListener(v -> {
startActivity(new Intent(view.getContext(), NewItemActivity.class));
});
}

private void initOnRefresh(final View view) {
Expand Down
231 changes: 231 additions & 0 deletions app/src/main/java/com/example/mobilelab/NewItemActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
package com.example.mobilelab;

import android.app.DatePickerDialog;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.webkit.MimeTypeMap;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.cloud.storage.Blob;
import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Bucket;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import com.squareup.picasso.Picasso;

import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Objects;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;

public class NewItemActivity extends AppCompatActivity {
private static final int IMAGE_REQUEST = 1;
private TextInputLayout titleField;
private TextInputLayout placeField;
private TextInputLayout dateField;
private TextInputLayout priceField;
private DatePickerDialog picker;
private ProgressBar progressBar;
private String imgDownloadLink;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_new_item);
Objects.requireNonNull(getSupportActionBar()).setTitle(getString(R.string.new_item));
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
initFields();
}

private void initFields() {
titleField = findViewById(R.id.title_wrapper);
placeField = findViewById(R.id.place_wrapper);
dateField = findViewById(R.id.date_wrapper);
progressBar = findViewById(R.id.progress_bar);
priceField = findViewById(R.id.price_wrapper);
findViewById(R.id.new_image_button).setOnClickListener(v -> openImage());
initButton();
initDatePicker();
}

private void initButton() {
findViewById(R.id.btn_create_item).setOnClickListener(v -> {
final String title = Objects.requireNonNull(titleField.getEditText()).getText().toString();
final String name = Objects.requireNonNull(placeField.getEditText()).getText().toString();
final String date = Objects.requireNonNull(dateField.getEditText()).getText().toString();
final String price = Objects.requireNonNull(priceField.getEditText()).getText().toString();
addItem(title, name, date, price, imgDownloadLink);
});
}

private void initDatePicker() {
final EditText date = dateField.getEditText();
Objects.requireNonNull(date).setOnClickListener(v -> {
final Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_MONTH);
int month = calendar.get(Calendar.MONTH);
int year = calendar.get(Calendar.YEAR);
picker = new DatePickerDialog(this, (view, year1, monthOfYear, dayOfMonth) ->
date.setText(String.format(getString(R.string.date_format),
dayOfMonth, monthOfYear + 1, year1)), year, month, day);
picker.show();
});
}

private void addItem(final String title, final String place, final String date, final String price, final String imgPath) {
if (!validate(title, place, date, price)) {
return;
}
final GoodsService service = getApplicationEx().getApiService();
Good good = new Good(title, place, date, price, imgPath);
Call<Good> call = service.addGood(good);
progressBar.setVisibility(View.VISIBLE);
call.enqueue(new Callback<Good>() {
@Override
public void onResponse(Call<Good> call, Response<Good> response) {
progressBar.setVisibility(View.INVISIBLE);
if (response.isSuccessful()) {
openMainActivity();
}
}

@Override
public void onFailure(Call<Good> call, Throwable t) {
progressBar.setVisibility(View.INVISIBLE);
Snackbar.make(findViewById(R.id.item_view), R.string.post_failed, Snackbar.LENGTH_LONG).show();
}
});
Comment on lines +95 to +116
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

цей метод троошки великий, треба подумати, якусь частину виокремити

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

чесно кажучи, не знайшла способу розділити цей метод. на мою думку 20 стрічок це не критично.

}

private void openImage() {
final Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, IMAGE_REQUEST);
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) {
new UploadImageTask().execute(data.getData());
}
}

private void showImage(final String photoUrl) {
final int TARGET_WIDTH = 200;
final int TARGET_HEIGHT = 200;
if (!photoUrl.isEmpty()) {
Picasso.get().load(photoUrl).resize(TARGET_WIDTH, TARGET_HEIGHT).into((ImageView) findViewById(R.id.item_image));
}
}

private String getFileExtension(Uri uri) {
ContentResolver contentResolver = Objects.requireNonNull(this).getContentResolver();
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
return mimeTypeMap.getExtensionFromMimeType(contentResolver.getType(uri));
}

public boolean validate(final String title, final String place, final String date, final String price) {
boolean valid = true;
if (Utils.validateString(title)) {
titleField.setError(null);
} else {
titleField.setError(getString(R.string.title_error));
valid = false;
}

if (Utils.validateString(place)) {
placeField.setError(null);
} else {
placeField.setError(getString(R.string.place_error));
valid = false;
}

if (!date.isEmpty()) {
dateField.setError(null);
} else {
dateField.setError(getString(R.string.date_error));
valid = false;
}

if (Utils.validatePrice(price)) {
priceField.setError(null);
} else {
priceField.setError(getString(R.string.price_error));
valid = false;
}

return valid;
Comment on lines +149 to +178
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

завеликий методи виходить, варто розбити на менші валідатори

}

public boolean onOptionsItemSelected(@NonNull MenuItem item) {
openMainActivity();
return true;
}

private void openMainActivity() {
final Intent myIntent = new Intent(getApplicationContext(), MainActivity.class);
startActivityForResult(myIntent, 0);
}

private App getApplicationEx() {
return ((App) Objects.requireNonNull(this.getApplication()));
}

private class UploadImageTask extends AsyncTask<Uri, Void, Void> {
protected void onPreExecute() {
progressBar.setVisibility(View.VISIBLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}

protected Void doInBackground(Uri... blobName) {
ServiceAccountCredentials credentials;
try {
credentials = ServiceAccountCredentials.fromStream(getResources().openRawResource(R.raw.bowlingsite));
Storage storage = StorageOptions.newBuilder().setProjectId("bowlingsite")
.setCredentials(credentials)
.build()
.getService();
final String bucketName = "www.bowling-iot.pp.ua";
final Bucket bucket = storage.get(bucketName);
final String imgPath = "img/" + blobName[0].getLastPathSegment() + "." + getFileExtension(blobName[0]);
final BlobId blobId = BlobId.of(bucket.getName(), imgPath);
final InputStream imageStream = getContentResolver().openInputStream(blobName[0]);
final BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("image/jpeg").build();
final Blob blob = storage.create(blobInfo, imageStream);
imgDownloadLink = blob.getMediaLink();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

@Override
protected void onPostExecute(Void result) {
showImage(imgDownloadLink);
progressBar.setVisibility(View.INVISIBLE);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
}
}
}
4 changes: 3 additions & 1 deletion app/src/main/java/com/example/mobilelab/ProfileFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.text.InputType;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
Expand Down Expand Up @@ -139,7 +140,7 @@ private void showEmailUpdateDialog() {

private void updateName() {
final String name = newName.getText().toString();
if (Utils.validateName(name)) {
if (Utils.validateString(name)) {
performNameUpdate(name);
} else {
newName.setError(getString(R.string.name_error));
Expand All @@ -150,6 +151,7 @@ private void performNameUpdate(String name) {
newName.setError(null);
final UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(name).build();
this.name.setText(name);
fuser.updateProfile(profileUpdates)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public boolean validate(final String email, final String name, final String phon
valid = false;
}

if (Utils.validateName(name)) {
if (Utils.validateString(name)) {
nameField.setError(null);
} else {
nameField.setError(getString(R.string.name_error));
Expand Down
Loading