Commit 2c215f50 authored by YONG-LIN SU's avatar YONG-LIN SU

新增案件功能 及 拍照儲存壓制功能

parent 108b1de2
package ecom.android.newparkapp;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
public class ModifyPhoto implements Runnable {
private final String path;
public ModifyPhoto(String path) {
this.path = path;
}
@Override
public void run() {
//Log.d("ModifyPhoto", " Begins Work : " + Thread.currentThread().getName());
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
bitmap = Common.turnPictureDegree(bitmap, path);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
Bitmap icon = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(icon);
Paint photoPaint = new Paint();
photoPaint.setDither(true);
photoPaint.setFilterBitmap(true);
Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
Rect dst = new Rect(0, 0, width, height);
canvas.drawBitmap(bitmap, src, dst, photoPaint);
Paint text = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
Paint stroke = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
int x = width / 38;
int y = width / 16;
text.setTextSize(y);
text.setTypeface(Typeface.DEFAULT_BOLD);
text.setColor(Color.WHITE);
text.setStyle(Paint.Style.FILL);//文字本體
stroke.setTextSize(y);
stroke.setTypeface(Typeface.DEFAULT_BOLD);
stroke.setColor(Color.BLACK);
stroke.setStyle(Paint.Style.STROKE);//文字外框
stroke.setStrokeWidth((float) width / 284);
String nowTime = Common.getDateAndTime(Calendar.getInstance());
canvas.drawText(nowTime, x, y, text);
canvas.drawText(nowTime, x, y, stroke);
canvas.save();
canvas.restore();
try (FileOutputStream out = new FileOutputStream(path)) {
icon.compress(Bitmap.CompressFormat.JPEG, 60, out);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (!bitmap.isRecycled()) {
bitmap.recycle();
}
if (!icon.isRecycled()) {
icon.recycle();
}
}
//Log.d("ModifyPhoto", " Ends Work : " + Thread.currentThread().getName());
}
}
package ecom.android.newparkapp.adapter;
import android.widget.Button;
import android.widget.TextView;
import androidx.databinding.BindingAdapter;
......@@ -7,6 +8,8 @@ import androidx.databinding.BindingAdapter;
import java.text.SimpleDateFormat;
import java.util.Date;
import ecom.android.newparkapp.entity.Case;
public class ConvertBindingAdapter {
@BindingAdapter("date2TimeString")
......
package ecom.android.newparkapp.dao;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
import ecom.android.newparkapp.entity.CasePhoto;
@Dao
public interface CasePhotoDao {
@Query("SELECT * FROM casephoto")
List<CasePhoto> getAll();
@Query("SELECT * FROM casephoto")
LiveData<List<CasePhoto>> getAllLiveData();
@Query("SELECT * FROM casephoto WHERE case_billing_number2 IN (:billingNumber2s)")
List<CasePhoto> loadAllByIds(String[] billingNumber2s);
@Insert
void insertAll(CasePhoto... casePhotos);
@Delete
void delete(CasePhoto casephoto);
@Query("DELETE FROM casephoto")
void deleteAll();
}
......@@ -9,6 +9,7 @@ import androidx.room.TypeConverters;
import ecom.android.newparkapp.R;
import ecom.android.newparkapp.dao.CaseDao;
import ecom.android.newparkapp.dao.CasePhotoDao;
import ecom.android.newparkapp.dao.RoadDao;
import ecom.android.newparkapp.dao.SpaceDao;
import ecom.android.newparkapp.dao.SpaceRateDao;
......@@ -20,6 +21,7 @@ import ecom.android.newparkapp.dao.VehicleBrandDao;
import ecom.android.newparkapp.dao.VehicleColorDao;
import ecom.android.newparkapp.dao.VehicleTypeDao;
import ecom.android.newparkapp.entity.Case;
import ecom.android.newparkapp.entity.CasePhoto;
import ecom.android.newparkapp.entity.LocationConverter;
import ecom.android.newparkapp.entity.Road;
import ecom.android.newparkapp.entity.Space;
......@@ -34,11 +36,12 @@ import ecom.android.newparkapp.entity.VehicleColor;
import ecom.android.newparkapp.entity.VehicleType;
// DataBase 一個資料庫一個,並涵蓋多個資料表
@Database(entities = {Case.class, Road.class, Space.class, SpaceRate.class, SpaceStatus.class, SpaceType.class, User.class, UserPermission.class, VehicleBrand.class, VehicleColor.class, VehicleType.class},
@Database(entities = {Case.class, CasePhoto.class, Road.class, Space.class, SpaceRate.class, SpaceStatus.class, SpaceType.class, User.class, UserPermission.class, VehicleBrand.class, VehicleColor.class, VehicleType.class},
version = 1)
@TypeConverters({LocationConverter.class, TimestampConverter.class})
public abstract class InfoDatabase extends RoomDatabase {
public abstract CaseDao caseDao();
public abstract CasePhotoDao casePhotoDao();
public abstract RoadDao roadDao();
public abstract SpaceDao spaceDao();
public abstract SpaceRateDao spaceRateDao();
......
......@@ -9,7 +9,10 @@ import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@Entity
public class Case {
......@@ -28,9 +31,6 @@ public class Case {
@ColumnInfo(name = "case_time")
public Date caseTime; // 開單時間
@Embedded(prefix = "road_")
public Road road;
@Embedded(prefix = "space_")
public Space space;
......@@ -47,13 +47,13 @@ public class Case {
public VehicleBrand vehicleBrand;
@ColumnInfo(name = "period_hour")
public float periodHour;
public float periodHour; // 停留幾個小時,根據該車格計時單位計算
@ColumnInfo(name = "final_expenses")
public int finalExpenses;
public int finalExpenses; // 最終停車費金額 = 總時數 * 費率
@ColumnInfo(name = "location")
public Location location;
public Location location; // gps 座標
@ColumnInfo(name = "bill_status")
public int billStatus;
......@@ -62,10 +62,10 @@ public class Case {
public int photoCount;
@ColumnInfo(name = "update_date")
public Date updateDate;
public Date updateDate; // 更新日期
@ColumnInfo(name = "final_time")
public Date finalTime;
public Date finalTime; // 最後一次續單時間
@ColumnInfo(name = "auto_pay")
public Boolean autoPay; // 自動扣款
......@@ -88,13 +88,15 @@ public class Case {
@Ignore
public String uploadPath;
public Case(String billingNumber2, String billingNumber1, User user, Date terminateDate, Date caseTime, Road road, Space space, String plateNumber, VehicleType vehicleType, VehicleColor vehicleColor, VehicleBrand vehicleBrand, float periodHour, int finalExpenses, Location location, int billStatus, int photoCount, Date updateDate, Date finalTime, Boolean autoPay, int agency, String shiftId) {
@Ignore
public CaseStatus caseStatus;
public Case(String billingNumber2, String billingNumber1, User user, Date terminateDate, Date caseTime, Space space, String plateNumber, VehicleType vehicleType, VehicleColor vehicleColor, VehicleBrand vehicleBrand, float periodHour, int finalExpenses, Location location, int billStatus, int photoCount, Date updateDate, Date finalTime, Boolean autoPay, int agency, String shiftId) {
this.billingNumber2 = billingNumber2;
this.billingNumber1 = billingNumber1;
this.user = user;
this.terminateDate = terminateDate;
this.caseTime = caseTime;
this.road = road;
this.space = space;
this.plateNumber = plateNumber;
this.vehicleType = vehicleType;
......@@ -114,4 +116,52 @@ public class Case {
public Case(){
}
/**
* 早班 晚班 標記
* @return A 或 B
*/
public String getShift(){
// TODO: 2022/7/29 資料庫新增早晚班參照後,取消該方法
return "A";
}
public String getUploadFileName() {
return billingNumber2 + ".txt";
}
/**
* 交換用檔案,串連各項資訊獲得
* @return 交換用檔案字串 A999;99B17V00189;20220817;10:43;A 中山路A;A216 2 1 中山路A;01 自小客;8052-LZ; ; ;0.5;25;Lat:24.1434911 Lon:120.7285887;1;1;
*/
public String getDetailString() {
DateFormat terminateDateFormat = new SimpleDateFormat("yyyymmdd");
String terminateDateString = terminateDateFormat.format(terminateDate); // 20220817
DateFormat caseTimeFormat = new SimpleDateFormat("HH:mm");
String caseTimeString = caseTimeFormat.format(caseTime); // 10:43
// TODO: 2022/7/29 加入GPS座標功能後,修改該處假資料
//String locationString = String.format("Lat:%f Lon:%f", location.getLatitude(), location.getLongitude()); // Lat:24.1434911 Lon:120.7285887
String locationString = "Lat:24.1434911 Lon:120.7285887";
return String.format(Locale.TAIWAN, "%s%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%.1f;%d;%s;%s;%d;\r\n",
getShift(), user.id,
billingNumber2,
terminateDateString,
caseTimeString,
space.road.getCombineInfo(),
space.getCombineInfo(),
vehicleType.getCombineInfo(),
plateNumber,
" ",// Car Color
" ",// Car Brand
periodHour,
finalExpenses,
locationString,
billStatus,
photoCount);
}
}
package ecom.android.newparkapp.entity;
import static androidx.room.ForeignKey.CASCADE;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.PrimaryKey;
@Entity(foreignKeys = @ForeignKey(entity = Case.class,
parentColumns = "billingNumber2",
childColumns = "case_billing_number2",
onDelete = CASCADE) )
public class CasePhoto {
@PrimaryKey
public int id;
@ColumnInfo(name = "case_billing_number2")
public String caseBillingNumber2;
@ColumnInfo(name = "photo_path")
public String photoPath;
@ColumnInfo(name = "plate_number")
public String plateNumber;
public CasePhoto(int id, String caseBillingNumber2, String photoPath, String plateNumber) {
this.id = id;
this.caseBillingNumber2 = caseBillingNumber2;
this.photoPath = photoPath;
this.plateNumber = plateNumber;
}
}
package ecom.android.newparkapp.entity;
public enum CaseStatus {
NEW, //尚未儲存之新案件
LIST, //已儲存之案件
CHANGED, //已儲存但有異動過之案件
LOCK //註銷之案件
}
......@@ -51,4 +51,8 @@ public class Road implements Parcelable {
return new Road[size];
}
};
public String getCombineInfo() {
return String.format("%s %s", id, name);
}
}
......@@ -52,18 +52,24 @@ public class Space implements Parcelable {
protected Space(Parcel in) {
id = in.readString();
road = in.readParcelable(Road.class.getClassLoader());
spaceType = in.readParcelable(SpaceType.class.getClassLoader());
fee = in.readInt();
spaceRate = in.readParcelable(SpaceRate.class.getClassLoader());
latitude = in.readFloat();
longitude = in.readFloat();
spaceStatus = in.readParcelable(SpaceStatus.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeParcelable(road, flags);
dest.writeParcelable(spaceType, flags);
dest.writeInt(fee);
dest.writeParcelable(spaceRate, flags);
dest.writeFloat(latitude);
dest.writeFloat(longitude);
dest.writeParcelable(spaceStatus, flags);
}
@Override
......@@ -82,4 +88,8 @@ public class Space implements Parcelable {
return new Space[size];
}
};
public String getCombineInfo() {
return String.format("%s %s %s %s", id, spaceRate.id, spaceType.id, road.name);
}
}
package ecom.android.newparkapp.entity;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
......@@ -8,7 +11,7 @@ import androidx.room.PrimaryKey;
* 停車收費頻率資料表
*/
@Entity
public class SpaceRate {
public class SpaceRate implements Parcelable {
@PrimaryKey
public int id;
......@@ -20,4 +23,32 @@ public class SpaceRate {
this.id = id;
this.perHours = perHours;
}
protected SpaceRate(Parcel in) {
id = in.readInt();
perHours = in.readFloat();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeFloat(perHours);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<SpaceRate> CREATOR = new Creator<SpaceRate>() {
@Override
public SpaceRate createFromParcel(Parcel in) {
return new SpaceRate(in);
}
@Override
public SpaceRate[] newArray(int size) {
return new SpaceRate[size];
}
};
}
package ecom.android.newparkapp.entity;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity
public class SpaceStatus {
public class SpaceStatus implements Parcelable {
@PrimaryKey
public int id;
......@@ -16,4 +19,32 @@ public class SpaceStatus {
this.id = id;
this.name = name;
}
protected SpaceStatus(Parcel in) {
id = in.readInt();
name = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<SpaceStatus> CREATOR = new Creator<SpaceStatus>() {
@Override
public SpaceStatus createFromParcel(Parcel in) {
return new SpaceStatus(in);
}
@Override
public SpaceStatus[] newArray(int size) {
return new SpaceStatus[size];
}
};
}
package ecom.android.newparkapp.entity;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
......@@ -8,7 +11,7 @@ import androidx.room.PrimaryKey;
* 停車格類型資料表
*/
@Entity
public class SpaceType {
public class SpaceType implements Parcelable {
@PrimaryKey
public int id;
......@@ -19,4 +22,32 @@ public class SpaceType {
this.id = id;
this.name = name;
}
protected SpaceType(Parcel in) {
id = in.readInt();
name = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<SpaceType> CREATOR = new Creator<SpaceType>() {
@Override
public SpaceType createFromParcel(Parcel in) {
return new SpaceType(in);
}
@Override
public SpaceType[] newArray(int size) {
return new SpaceType[size];
}
};
}
......@@ -50,4 +50,8 @@ public class VehicleType implements Parcelable {
parcel.writeInt(id);
parcel.writeString(name);
}
public String getCombineInfo() {
return String.format("%s %s",id, name);
}
}
......@@ -7,6 +7,7 @@ import java.util.concurrent.Executors;
import ecom.android.newparkapp.R;
import ecom.android.newparkapp.dao.CaseDao;
import ecom.android.newparkapp.dao.CasePhotoDao;
import ecom.android.newparkapp.dao.RoadDao;
import ecom.android.newparkapp.dao.SpaceDao;
import ecom.android.newparkapp.dao.SpaceRateDao;
......@@ -38,6 +39,7 @@ public class InfoRepository {
public RoadDao roadDao;
public SpaceDao spaceDao;
public CaseDao caseDao;
public CasePhotoDao casePhotoDao;
public InfoRepository(Application application) {
infoDatabase = InfoDatabase.getInstance(application);
......@@ -55,6 +57,7 @@ public class InfoRepository {
roadDao = infoDatabase.roadDao();
spaceDao = infoDatabase.spaceDao();
caseDao = infoDatabase.caseDao();
casePhotoDao = infoDatabase.casePhotoDao();
executorService = Executors.newFixedThreadPool(application.getResources().getInteger(R.integer.number_db_thread_pool));
}
......
......@@ -46,10 +46,13 @@ public class MainActivity extends AppCompatActivity {
dataBinding.setUserViewModel(userViewModel);
// 註冊權限請求結果處理
resultLauncherRegister();
// 檢查權限
permissionRequest();
// 監聽權限驗證變化
// 有權限再綁定按鈕功能
hasPermissions.observe(this, has -> {
if (has){
eventBinding();
......@@ -57,6 +60,9 @@ public class MainActivity extends AppCompatActivity {
});
}
/**
* 權限請求方法
*/
private void permissionRequest(){
// 參考資料 https://developer.android.com/training/permissions/requesting
hasPermissions.setValue(false);
......@@ -67,6 +73,9 @@ public class MainActivity extends AppCompatActivity {
}
}
/**
* @return 檢查所有權限
*/
private boolean checkPermissions(){
boolean ret = true;
for (String permission : permissions){
......@@ -78,6 +87,9 @@ public class MainActivity extends AppCompatActivity {
return ret;
}
/**
* 註冊 registerForActivityResult 事件處理
*/
private void resultLauncherRegister(){
requestPermissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestMultiplePermissions(),
......
......@@ -4,15 +4,23 @@ import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import androidx.databinding.DataBindingUtil;
import androidx.lifecycle.ViewModelProvider;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.widget.Toast;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
......@@ -35,8 +43,11 @@ public class T02StartActivity extends AppCompatActivity {
private ActivityResultLauncher vehicleTypeResultLauncher;
private ActivityResultLauncher spaceResultLauncher;
private ActivityResultLauncher plateNumberResultLauncher;
private ActivityResultLauncher takePhotosActivityResultLauncher;
private User currentUser;
private File photoFile;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......@@ -62,10 +73,16 @@ public class T02StartActivity extends AppCompatActivity {
dataBinding.btnVehicleType.setOnClickListener(v -> btnVehicleTypeOnClicked());
dataBinding.btnTimeNow.setOnClickListener(v -> btnTimeNowOnClicked());
dataBinding.btnPlateNumber.setOnClickListener(v-> btnPlateNumberOnClicked());
dataBinding.btnPhotograph.setOnClickListener(v -> btnPhotographOnClicked());
dataBinding.btnNewPage.setOnClickListener(v -> btnNewPageOnClicked());
dataBinding.btnPageDown.setOnClickListener(v -> btnPageDownOnClicked());
dataBinding.btnPageUp.setOnClickListener(v -> btnPageUpOnClicked());
dataBinding.btnStartBack.setOnClickListener(v -> {finish();});
}
private void resultLauncherRegister(){
vehicleTypeResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK && result.getData()!=null){
VehicleType selectedVehicleType = result.getData().getParcelableExtra("VehicleType");
......@@ -87,9 +104,20 @@ public class T02StartActivity extends AppCompatActivity {
plateNumberResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null){
String plateNumber = result.getData().getStringExtra("PlateNumber");
t02StartViewModel.setPlateNumber(plateNumber);
}
});
takePhotosActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK){
if ( photoFile == null){
return;
}
t02StartViewModel.takeNewPhoto(photoFile);
}
});
}
private void observeBinding(){
......@@ -133,4 +161,58 @@ public class T02StartActivity extends AppCompatActivity {
intent.setClass(this, T02KeyInPlateNumberActivity.class);
plateNumberResultLauncher.launch(intent);
}
private void btnPhotographOnClicked(){
Case currentCase = t02StartViewModel.getCurrentCase().getValue();
Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
takePhotoIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// 檢查是否已取得權限
if (takePhotoIntent.resolveActivity(getPackageManager()) == null) return;
String day = new SimpleDateFormat("yyyyMMdd").format(new Date());
String path = Environment.getExternalStorageDirectory() + getString(R.string.sysDataPhoto_path) + day;
File temp = new File(path);
if (!temp.exists()) {
if (!temp.mkdirs()) {
Toast.makeText(this, "目錄 " + temp.getName() + " 新增失敗!", Toast.LENGTH_LONG).show();
return;
}
}
photoFile = new File(path, "/" + currentCase.billingNumber2 + currentCase.photoCount + ".jpg");
Uri photoURI = FileProvider.getUriForFile(this, "ecom.android.newparkapp.fileprovider", photoFile);
takePhotoIntent.putExtra(MediaStore.EXTRA_SCREEN_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
takePhotosActivityResultLauncher.launch(takePhotoIntent);
}
private void btnNewPageOnClicked(){
if (!t02StartViewModel.caseDataConfirm()){
// 資料不完整
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("檔案保存");
builder.setMessage("資料不完整,請重新確認");
builder.setPositiveButton("清空",(dialogInterface, i) -> {
t02StartViewModel.initCurrentCase();
});
builder.setNegativeButton("返回",(dialogInterface, i) -> {
dialogInterface.dismiss();
});
builder.create().show();
}else {
// 資料完整
// 儲存
t02StartViewModel.saveCurrentCase();
}
}
private void btnPageDownOnClicked(){
t02StartViewModel.pageDown();
}
private void btnPageUpOnClicked(){
t02StartViewModel.pageUp();
}
}
\ No newline at end of file
package ecom.android.newparkapp.viewModel;
import android.app.Application;
import android.content.Context;
import android.media.MediaScannerConnection;
import android.os.Environment;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModelProvider;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import ecom.android.newparkapp.Common;
import ecom.android.newparkapp.ModifyPhoto;
import ecom.android.newparkapp.R;
import ecom.android.newparkapp.entity.Case;
import ecom.android.newparkapp.entity.CasePhoto;
import ecom.android.newparkapp.entity.CaseStatus;
import ecom.android.newparkapp.entity.Road;
import ecom.android.newparkapp.entity.Space;
import ecom.android.newparkapp.entity.User;
import ecom.android.newparkapp.entity.VehicleBrand;
import ecom.android.newparkapp.entity.VehicleColor;
import ecom.android.newparkapp.entity.VehicleType;
import ecom.android.newparkapp.repository.InfoRepository;
......@@ -31,12 +33,16 @@ import ecom.android.newparkapp.repository.InfoRepository;
public class T02StartViewModel extends AndroidViewModel {
private MutableLiveData<Case> currentCase = new MutableLiveData<>();
private List<Case> cases;
private int caseCursor = 0;
private LiveData<List<VehicleType>> vehicleTypes;
private LiveData<List<Road>> roads;
private LiveData<List<Space>> spaces;
private InfoRepository infoRepository;
private MutableLiveData<User> currentUser = new MutableLiveData<>();
private List<CasePhoto> tempCasePhoto = new ArrayList<>();
public T02StartViewModel(@NonNull Application application) {
super(application);
......@@ -45,6 +51,7 @@ public class T02StartViewModel extends AndroidViewModel {
vehicleTypes = infoRepository.vehicleTypeDao.getAllLiveData();
roads = infoRepository.roadDao.getAllLiveData();
spaces = infoRepository.spaceDao.getAllLiveData();
cases = infoRepository.caseDao.getAll();
}
public LiveData<List<VehicleType>> getVehicleTypes(){
......@@ -63,9 +70,44 @@ public class T02StartViewModel extends AndroidViewModel {
public void setSpace(Space space){
Case tempCase = currentCase.getValue();
tempCase.space = space;
// 取得車格後,更新費用及時間
if (tempCase.caseStatus == CaseStatus.NEW){
int addCount = calcPeriodHourCount(tempCase);
tempCase.periodHour = addCount * space.spaceRate.perHours;
tempCase.finalExpenses = addCount * space.fee;
}
currentCase.setValue(tempCase);
}
/**
* 計算 累加 時數的次數
* @param thisCase 當前案件
* @return
*/
private int calcPeriodHourCount(Case thisCase){
int new_addCount = 0;
if (thisCase.caseTime == null || thisCase.finalTime == null || thisCase.space == null || thisCase.space.spaceRate == null){
return new_addCount;
}
Calendar caseCalendar = Calendar.getInstance();
caseCalendar.setTime(thisCase.caseTime);
caseCalendar.set(Calendar.SECOND, 0);
Calendar finalCalendar = Calendar.getInstance();
finalCalendar.setTime(thisCase.finalTime);
finalCalendar.set(Calendar.SECOND, 0);
do {//利用時間差算出累加次數
caseCalendar.add(Calendar.MINUTE, (int) (thisCase.space.spaceRate.perHours * 60));
new_addCount += 1;
} while (caseCalendar.before(finalCalendar));
return new_addCount;
}
public void updateCaseDate(){
Case tempCase = currentCase.getValue();
tempCase.caseTime = Calendar.getInstance().getTime();
......@@ -79,18 +121,126 @@ public class T02StartViewModel extends AndroidViewModel {
}
public void initCurrentCase(){
// 清空佔存
tempCasePhoto.clear();
currentCase.setValue(newCase());
}
private Case newCase(){
Case newCase = new Case();
newCase.caseStatus = CaseStatus.NEW;
newCase.user = currentUser.getValue();
newCase.caseTime = Calendar.getInstance().getTime();
newCase.finalTime = Calendar.getInstance().getTime();
generateBillingNumber(newCase);
return newCase;
}
public void saveCurrentCase(){
// TODO: 2022/7/29 case資料寫入db
Case tempCase = currentCase.getValue();
switch (tempCase.caseStatus){
case NEW:
infoRepository.executorService.execute(() -> {
infoRepository.caseDao.insertAll(tempCase);
for (int i = 0 ; i < tempCasePhoto.size(); i++){
infoRepository.casePhotoDao.insertAll(tempCasePhoto.get(i));
}
tempCasePhoto.clear();
//存進併檔用文字檔
Common.writeTXT(getApplication(), tempCase.datePath, tempCase.userDateFileName, tempCase.getDetailString());
updateIdx(tempCase);
Common.writeTXT(getApplication(), tempCase.uploadPath, tempCase.getUploadFileName(), tempCase.getDetailString());
// 跳至新單
currentCase.postValue(newCase());
});
break;
case LIST:
break;
case CHANGED:
break;
case LOCK:
break;
default:
break;
}
}
/**
* @param photoFile 拍照回傳檔案
*/
public void takeNewPhoto(File photoFile){
Case tempCase = currentCase.getValue();
// 更新照片數量
tempCase.photoCount+=1;
// 取得完整路徑
final String path = photoFile.getAbsolutePath();
// TODO: 2022/7/29 加入車牌辨識功能
String newPlateNumber = "8050-LZ";
CasePhoto newCasePhoto = new CasePhoto(0, tempCase.billingNumber2, path, newPlateNumber);
tempCasePhoto.add(newCasePhoto);
// 為圖片壓制浮水印
Thread ModifyPhotoT = new Thread(new ModifyPhoto(path), "ModifyPhoto_Thread");
ModifyPhotoT.start();
// 重新搜尋檔案
MediaScannerConnection.scanFile(getApplication().getApplicationContext(), new String[]{path}, null, null);
// 更新當前案件
currentCase.setValue(tempCase);
}
/**
* 檢查案件資料是否完整
* @return true or fasle
*/
public boolean caseDataConfirm(){
Case tempCase = currentCase.getValue();
// 單號檢查
if (tempCase.billingNumber2.trim().isEmpty() || tempCase.billingNumber2.length() != 11){
return false;
}
// 檢查時間
// 檢查車格
if (tempCase.space == null || tempCase.space.id.isEmpty() || tempCase.space.road == null || tempCase.space.road.id.isEmpty()){
return false;
}
// 檢查車種
if (tempCase.vehicleType == null || tempCase.vehicleType.name.trim().isEmpty()){
return false;
}
// 檢查車牌
if (!Common.plateRuleCheck(tempCase.plateNumber)){
return false;
}
// 檢查照片
if (tempCase.photoCount == 0){
return false;
}
return true;
}
/**
* 產生單號
* 1.依據日期產生第一段條碼
......@@ -112,7 +262,7 @@ public class T02StartViewModel extends AndroidViewModel {
// 初始化目錄
thisCase.datePath = Environment.getExternalStorageDirectory() + getApplication().getString(R.string.sysData_path) + Common.getDate(caseCalendar, false);
thisCase.fileNameBackup = "/" + thisCase.shiftId;//[A]早/晚
thisCase.fileNameBackup = "/" + thisCase.getShift();//[A]早/晚
thisCase.fileNameBackup += userID + "-";//[85]使用者代號 [-]
thisCase.fileNameBackup += Common.getDate(caseCalendar, false);//[20200114]日期
thisCase.userDateFileName = thisCase.fileNameBackup + ".txt";//[A][85][-][20200114][.txt]
......@@ -141,8 +291,9 @@ public class T02StartViewModel extends AndroidViewModel {
thisCase.billingNumber2 = BN2.toString();
BN2.append(Common.check(thisCase.billingNumber1, thisCase.billingNumber2)); //2碼檢查碼->[19]
thisCase.billingNumber2 = BN2.toString();
}
// TODO: 2022/7/29 加入與資料庫 billingNumber2 欄位比較是否重複
}
/**
* 取得流水號,用來產生第二段條碼
......@@ -178,4 +329,21 @@ public class T02StartViewModel extends AndroidViewModel {
}
/**
* 案件頁面切換下一頁
*/
public void pageDown() {
int casesSize = cases.size();
// 判斷是否到底了
if (casesSize > caseCursor){
}
}
/**
* 案件頁面切換上一頁
*/
public void pageUp() {
}
}
......@@ -398,7 +398,7 @@ tools:layout_editor_absoluteY="25dp">
android:layout_weight="0.53"
android:gravity="center"
android:textSize="24sp"
android:text="@{String.valueOf(t02StartViewModel.currentCase.finalTime)}"/>
android:text="@{String.valueOf(t02StartViewModel.currentCase.periodHour)}"/>
<TextView
android:id="@+id/textView3"
......
A999;99B17V00189;20220817;10:43;A 中山路A;A216 2 1 中山路A;01 自小客;8052-LZ; ; ;0.5;25;Lat:24.1434911 Lon:120.7285887;1;1;
A999;99B17V00189;20220817;10:43;A 中山路A;A216 2 1 中山路A;01 自小客;8052-LZ; ; ;0.5;25;Lat:24.1434911 Lon:120.7285887;1;1;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment