├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── example
│ │ └── woodinvoicetest
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── example
│ │ │ └── woodinvoicetest
│ │ │ ├── AddCustomerName.kt
│ │ │ ├── Common.kt
│ │ │ ├── ConfirmEverything.kt
│ │ │ ├── DataClasses.kt
│ │ │ ├── InvoiceReviewScreen.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── QuantityAndPrice.kt
│ │ │ ├── SendToServer.kt
│ │ │ ├── ShowInvoices.kt
│ │ │ ├── ShowSingleInvoice.kt
│ │ │ ├── WoodInvoicesDao.kt
│ │ │ ├── WoodInvoicesDatabase.kt
│ │ │ ├── WoodInvoicesRepository.kt
│ │ │ ├── WoodInvoicesViewModel.kt
│ │ │ ├── WoodInvoicesViewModelFactory.kt
│ │ │ ├── WoodProducts.kt
│ │ │ └── utils.kt
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── background.jpg
│ │ ├── button_shape.xml
│ │ ├── choose_button.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── my_cancel_button.xml
│ │ ├── my_delete_icon.xml
│ │ ├── my_edit_icon.xml
│ │ └── subbackground.jpg
│ │ ├── layout-land
│ │ ├── activity_add_customer_name.xml
│ │ ├── activity_confirm_everything.xml
│ │ ├── activity_invoice_review_screen.xml
│ │ ├── activity_main.xml
│ │ ├── activity_quantity_and_price.xml
│ │ └── activity_woodproducts.xml
│ │ ├── layout-sw600dp
│ │ ├── activity_add_customer_name.xml
│ │ ├── activity_confirm_everything.xml
│ │ ├── activity_invoice_review_screen.xml
│ │ ├── activity_main.xml
│ │ ├── activity_quantity_and_price.xml
│ │ └── activity_woodproducts.xml
│ │ ├── layout
│ │ ├── activity_add_customer_name.xml
│ │ ├── activity_confirm_everything.xml
│ │ ├── activity_invoice_review_screen.xml
│ │ ├── activity_main.xml
│ │ ├── activity_quantity_and_price.xml
│ │ ├── activity_send_to_server.xml
│ │ ├── activity_show_invoices.xml
│ │ ├── activity_show_single_invoice.xml
│ │ ├── activity_woodproducts.xml
│ │ └── alert_dialog_with_edittext.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── my_ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── my_ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── my_ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── my_ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_round.png
│ │ └── my_ic_launcher.png
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ └── network_security_config.xml
│ └── test
│ └── java
│ └── com
│ └── example
│ └── woodinvoicetest
│ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | # Uncomment the following line in case you need and you don't have the release build type files in your app
18 | # release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/
42 | .idea/workspace.xml
43 | .idea/tasks.xml
44 | .idea/gradle.xml
45 | .idea/assetWizardSettings.xml
46 | .idea/dictionaries
47 | .idea/libraries
48 | # Android Studio 3 in .gitignore file.
49 | .idea/caches
50 | .idea/modules.xml
51 | # Comment next line if keeping position of elements in Navigation Editor is relevant for you
52 | .idea/navEditor.xml
53 |
54 | # Keystore files
55 | # Uncomment the following lines if you do not want to check your keystore files in.
56 | #*.jks
57 | #*.keystore
58 |
59 | # External native build folder generated in Android Studio 2.2 and later
60 | .externalNativeBuild
61 | .cxx/
62 |
63 | # Google Services (e.g. APIs or Firebase)
64 | # google-services.json
65 |
66 | # Freeline
67 | freeline.py
68 | freeline/
69 | freeline_project_description.json
70 |
71 | # fastlane
72 | fastlane/report.xml
73 | fastlane/Preview.html
74 | fastlane/screenshots
75 | fastlane/test_output
76 | fastlane/readme.md
77 |
78 | # Version control
79 | vcs.xml
80 |
81 | # lint
82 | lint/intermediates/
83 | lint/generated/
84 | lint/outputs/
85 | lint/tmp/
86 | # lint/reports/
87 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Take Orders APP
2 | It is an Android App that I wrote to take orders from the customers and establish invoices.
3 | It is similar to the applications which restaurants use to get food orders from the visitors.
4 | I designed the app for our family company that sells sawn wood and plywood.
5 | The wood products have width, thickness, and length as main properties.
6 | The products can have extra specific features such as large or small, wet or dry, etc.
7 | I wrote the App in Kotlin
8 |
9 | ## Requirements and installation
10 |
11 | 1. You need to download [Android Studio](https://developer.android.com/studio)
12 | 2. Clone the Repo
13 |
14 | ```shell script
15 | $ git clone https://github.com/MaherDeeb/take_orders_app.git
16 | ```
17 | 3. Build APK
18 |
19 | ## App flow:
20 |
21 |
22 | Check the Demo [here](https://youtu.be/8MdLv3h-j-o)
23 |
24 | ## Next Step
25 |
26 | The App is a part of a data pipeline. The pipeline contains several components:
27 |
28 | 1. Wood orders taker App (this app): An android app that the workers use to collect orders from the customers. After confirming the payment, the App sends the data to the remote server.
29 | 2. Python-based remote server: It is a simple VM that receives and stores the data in the database. It sends a notification to keep the manger up to date after every transaction.
30 | 3. Invoices viewer App: It is a simple android app that the manager uses to view the notifications which the server sends. The manager can fetch the data from the server and check the invoices.
31 | 4. CenterAI: it is a computer vision framework that I wrote in Python on top of Pytorch. CenterAI enables training models for computer vision similar to other frameworks such as fastai but with a more convenient interface.
32 | 5. Wood QQ (not sure about the final name yet) App: It is an android app that the customer can use to count the sawn wood pieces and measure the wood quality from images.
33 | 6. An experimental environment to analyze the data. The data should answer some important business questions such as the next best offer for each customer, the customer lifetime value, and so on.
34 | 7. A simple dashboard helps the manager observe how the company does in the short and long terms.
35 |
36 | For more information you, check my [article](https://www.linkedin.com/pulse/ai-value-season-1-episode-maher-deeb)
37 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-kapt'
4 | apply plugin: 'kotlin-android-extensions'
5 |
6 | android {
7 | compileSdkVersion 29
8 | buildToolsVersion "29.0.3"
9 |
10 | defaultConfig {
11 | applicationId "com.example.woodinvoicetest"
12 | minSdkVersion 16
13 | targetSdkVersion 29
14 | versionCode 1
15 | versionName "1.0"
16 |
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 |
20 | buildTypes {
21 | release {
22 | minifyEnabled false
23 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
24 | }
25 | }
26 |
27 | dataBinding {
28 | enabled = true
29 | }
30 |
31 | }
32 |
33 | dependencies {
34 | implementation fileTree(dir: 'libs', include: ['*.jar'])
35 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
36 | implementation 'androidx.appcompat:appcompat:1.1.0'
37 | implementation 'androidx.core:core-ktx:1.3.0'
38 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
39 | testImplementation 'junit:junit:4.12'
40 | androidTestImplementation 'androidx.test.ext:junit:1.1.1'
41 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
42 | implementation 'androidx.gridlayout:gridlayout:1.0.0'
43 | implementation "org.jetbrains.kotlin:kotlin-script-runtime:1.3.72"
44 | implementation 'com.karumi:dexter:6.1.2'
45 | implementation 'com.itextpdf:itextg:5.5.10'
46 | // Room and Lifecycle dependencies
47 | //noinspection GradleDependency
48 | implementation "androidx.room:room-runtime:$version_room"
49 | kapt "androidx.room:room-compiler:$version_room"
50 | //noinspection GradleDependency
51 | implementation "androidx.lifecycle:lifecycle-extensions:$version_lifecycle_extensions"
52 | //noinspection GradleDependency
53 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$version_lifecycle_extensions"
54 | //noinspection GradleDependency
55 | // implementation "androidx.lifecycle:lifecycle-livedata-ktx:$version_lifecycle_extensions"
56 | //noinspection LifecycleAnnotationProcessorWithJava8
57 | kapt "androidx.lifecycle:lifecycle-compiler:$version_lifecycle_extensions"
58 | kapt "com.android.databinding:compiler:3.6.3"
59 | implementation 'com.jakewharton.threetenabp:threetenabp:1.2.1'
60 | // Coroutines
61 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_coroutine"
62 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version_coroutine"
63 | implementation 'com.google.code.gson:gson:2.8.5'
64 | implementation 'com.android.volley:volley:1.1.1'
65 | //noinspection GradleDependency
66 | implementation "com.google.android.material:material:1.3.0-alpha01"
67 | }
68 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/woodinvoicetest/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.example.woodinvoicetest", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/AddCustomerName.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.content.DialogInterface
4 | import android.content.Intent
5 | import androidx.appcompat.app.AppCompatActivity
6 | import android.os.Bundle
7 | import android.text.Editable
8 | import android.text.TextWatcher
9 | import android.widget.Toast
10 | import androidx.appcompat.app.AlertDialog
11 | import kotlinx.android.synthetic.main.activity_add_customer_name.*
12 | import java.util.*
13 | import kotlin.math.round
14 |
15 | class AddCustomerName : AppCompatActivity() {
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContentView(R.layout.activity_add_customer_name)
20 | totalSum.text = decimalFormatChanger.format(ordersInvoice.invoiceTotalSum).toString()
21 |
22 |
23 | soldInputs.addTextChangedListener(object : TextWatcher {
24 | override fun afterTextChanged(s: Editable) {}
25 | override fun beforeTextChanged(
26 | s: CharSequence, start: Int,
27 | count: Int, after: Int
28 | ) {
29 | }
30 |
31 | override fun onTextChanged(
32 | s: CharSequence, start: Int,
33 | before: Int, count: Int
34 | ) {
35 | if (s.isNotEmpty()) {
36 | var totalSumWithSold = ordersInvoice.invoiceTotalSum - s.toString().toDouble()
37 | totalSumWithSold = round(totalSumWithSold * 100) / 100
38 | totalSum.text = decimalFormatChanger.format(totalSumWithSold).toString()
39 |
40 | }
41 | }
42 | })
43 | confirmPayment.setOnClickListener { goToConfirmEverything() }
44 | cancelInvoiceButton.setOnClickListener { resetInvoiceYesNoDialog() }
45 | backButton.setOnClickListener { goToInvoiceReviewScreen() }
46 | }
47 |
48 | private fun goToConfirmEverything() {
49 | if (customerNameInput.text.isNotEmpty()) {
50 | ordersInvoice.customerName = customerNameInput.text.toString()
51 | ordersInvoice.invoiceId = getAndShowDate()
52 | if (soldInputs.text.isEmpty()) {
53 | ordersInvoice.invoiceSold = 0.0
54 | } else {
55 | ordersInvoice.invoiceSold = soldInputs.text.toString().toDouble()
56 | }
57 |
58 | ordersInvoice.invoiceNotes = invoiceNotesEditText.text.toString()
59 |
60 | val intent = Intent(this, ConfirmEverything::class.java)
61 | startActivity(intent)
62 | } else {
63 | Toast.makeText(
64 | this,
65 | getString(R.string.missingCustomerNameMessageError),
66 | Toast.LENGTH_SHORT
67 | ).show()
68 | }
69 | }
70 |
71 | private fun cancelInvoice() {
72 | ordersInvoice = InvoiceObjectClass()
73 | orderedProduct = OrderedProduct()
74 | val intent = Intent(this, MainActivity::class.java)
75 | startActivity(intent)
76 | }
77 |
78 | private fun resetInvoiceYesNoDialog() {
79 | lateinit var dialog: AlertDialog
80 | val builder = AlertDialog.Builder(this)
81 | builder.setTitle(getString(R.string.cancelInvoiceMessageTitle))
82 | builder.setMessage(getString(R.string.doYouWantToCancelInvoiceMessage))
83 | val dialogClickListener = DialogInterface.OnClickListener { _, which ->
84 | when (which) {
85 | DialogInterface.BUTTON_POSITIVE -> cancelInvoice()
86 | DialogInterface.BUTTON_NEGATIVE -> doNothing()
87 | }
88 | }
89 | builder.setPositiveButton(getString(R.string.yesAnswer), dialogClickListener)
90 | builder.setNegativeButton(getString(R.string.noAnswer), dialogClickListener)
91 | dialog = builder.create()
92 | dialog.show()
93 | }
94 |
95 | private fun goToInvoiceReviewScreen() {
96 | val intent = Intent(this, InvoiceReviewScreen::class.java)
97 | startActivity(intent)
98 | }
99 |
100 | override fun onBackPressed() {
101 | goToInvoiceReviewScreen()
102 | }
103 | }
104 |
105 | fun getAndShowDate(): String {
106 | return Calendar.getInstance().timeInMillis.toString()
107 |
108 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/Common.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import java.io.File
6 |
7 | object Common {
8 | fun getAppPath(context: Context): String {
9 | val dir = File(
10 | android.os.Environment.getExternalStorageDirectory().toString() +
11 | File.separator + "invoices" + File.separator
12 | )
13 | if (!dir.exists()) {
14 | dir.mkdirs()
15 | }
16 | return dir.path + File.separator
17 | }
18 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/ConfirmEverything.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.content.Intent
4 | import androidx.appcompat.app.AppCompatActivity
5 | import android.os.Bundle
6 | import android.util.Log
7 | import android.widget.Toast
8 | import androidx.databinding.DataBindingUtil
9 | import androidx.lifecycle.ViewModelProviders
10 | import com.android.volley.DefaultRetryPolicy
11 | import com.android.volley.Request
12 | import com.android.volley.Response
13 | import com.android.volley.toolbox.StringRequest
14 | import com.android.volley.toolbox.Volley
15 | import com.itextpdf.text.*
16 | import com.itextpdf.text.pdf.PdfWriter
17 | import com.karumi.dexter.Dexter
18 | import com.karumi.dexter.PermissionToken
19 | import com.karumi.dexter.listener.PermissionRequest
20 | import kotlinx.android.synthetic.main.activity_confirm_everything.*
21 | import java.io.File
22 | import java.io.FileOutputStream
23 | import com.example.woodinvoicetest.databinding.ActivityConfirmEverythingBinding
24 | import com.google.gson.Gson
25 | import com.karumi.dexter.MultiplePermissionsReport
26 | import com.karumi.dexter.listener.multi.MultiplePermissionsListener
27 | import java.lang.Exception
28 |
29 | class ConfirmEverything : AppCompatActivity() {
30 | private val filename: String = "invoice.pdf"
31 |
32 | override fun onCreate(savedInstanceState: Bundle?) {
33 | super.onCreate(savedInstanceState)
34 | val binding: ActivityConfirmEverythingBinding =
35 | DataBindingUtil.setContentView(this, R.layout.activity_confirm_everything)
36 |
37 | Toast.makeText(this, getString(R.string.messageConfirmPayment), Toast.LENGTH_LONG).show()
38 |
39 | val application = requireNotNull(this).application
40 | val dataSource = WoodInvoicesDatabase.getInstance(application).woodInvoiceDao
41 | val woodInvoicesViewModelFactory = WoodInvoicesViewModelFactory(dataSource, application)
42 | val woodInvoicesViewModel = ViewModelProviders.of(this, woodInvoicesViewModelFactory)
43 | .get(WoodInvoicesViewModel::class.java)
44 |
45 | showInvoice.setOnClickListener { goToShowOneInvoice() }
46 | backToMainScreen.setOnClickListener { finishInvoice() }
47 |
48 | Dexter.withContext(this)
49 | .withPermissions(
50 | android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
51 | android.Manifest.permission.INTERNET
52 | )
53 | .withListener(object : MultiplePermissionsListener {
54 | override fun onPermissionsChecked(p0: MultiplePermissionsReport?) {
55 | printInvoiceButton.setOnClickListener { sendInvoiceToPrinter() }
56 | if (ordersInvoice.sendToServer == "false") {
57 | val jsonOrderedInvoice = dataClassToJson()
58 | sendInvoiceToServer(jsonOrderedInvoice)
59 | ordersInvoice.sendToServer = "true"
60 | }
61 | }
62 |
63 | override fun onPermissionRationaleShouldBeShown(
64 | p0: MutableList?,
65 | p1: PermissionToken?
66 | ) {
67 | doNothing()
68 | }
69 | })
70 | .check()
71 |
72 | binding.lifecycleOwner = this
73 | binding.woodInvoicesViewModel = woodInvoicesViewModel
74 | if (ordersInvoice.savedToDatabase == "false") {
75 | woodInvoicesViewModel.onConfirmEverything()
76 | ordersInvoice.savedToDatabase = "true"
77 | }
78 |
79 | }
80 |
81 |
82 | fun sendInvoiceToPrinter() {
83 | val pdfPath = Common.getAppPath(this@ConfirmEverything) + filename
84 | createPDFFile(pdfPath)
85 | // Toast.makeText(this, "the pdf path is $pdfPath", Toast.LENGTH_SHORT).show()
86 | Toast.makeText(this, "This feature is in development", Toast.LENGTH_LONG).show()
87 | }
88 |
89 | override fun onBackPressed() {
90 | finishInvoice()
91 | }
92 |
93 | private fun finishInvoice() {
94 | ordersInvoice = InvoiceObjectClass()
95 | orderedProduct = OrderedProduct()
96 | val intent = Intent(this, MainActivity::class.java)
97 | startActivity(intent)
98 | }
99 |
100 | private fun createPDFFile(path: String) {
101 | if (File(path).exists()) {
102 | File(path).delete()
103 | print("pdf deleted")
104 | }
105 | val document = Document()
106 | PdfWriter.getInstance(document, FileOutputStream(path))
107 | document.open()
108 | document.pageSize = PageSize.A4
109 | document.addCreationDate()
110 |
111 | val colorAccent = BaseColor(0, 153, 204, 255)
112 | val headingFontSize = 20.0f
113 | val valueFontSize = 26.0f
114 |
115 | val titleStyle = Font(Font.FontFamily.COURIER, 36.0f, Font.NORMAL, BaseColor.BLACK)
116 | addNewItem(document, "Invoice", Element.ALIGN_CENTER, titleStyle)
117 | document.close()
118 | Toast.makeText(this, "the pdf path is $path", Toast.LENGTH_SHORT).show()
119 | Toast.makeText(this, getString(R.string.messageConfirmPrinting), Toast.LENGTH_LONG).show()
120 |
121 | }
122 |
123 | @Throws(DocumentException::class)
124 | private fun addNewItem(document: Document, text: String, align: Int, style: Font) {
125 | val chunk = Chunk(text, style)
126 | val p = Paragraph(chunk)
127 | p.alignment = align
128 | document.add(p)
129 | }
130 |
131 | fun dataClassToJson(): String {
132 | val gson = Gson()
133 | val jsonTut: String = gson.toJson(ordersInvoice)
134 | Log.i("json", "the json object: $jsonTut")
135 | return jsonTut
136 | }
137 |
138 | fun sendInvoiceToServer(jsonOrderedInvoice: String) {
139 | val externalURL = getString(R.string.externalServerUrl)
140 | val internalURL = getString(R.string.internalServerUrl)
141 | val stringRequest: StringRequest = object : StringRequest(Request.Method.POST, internalURL,
142 | Response.Listener { response ->
143 | try {
144 | Log.i(
145 | "server",
146 | "the invoice was sent to the server and the response is $response"
147 | )
148 | Toast.makeText(
149 | this,
150 | getString(R.string.messageConfirmSentToServer),
151 | Toast.LENGTH_LONG
152 | )
153 | .show()
154 | } catch (e: Exception) {
155 | Toast.makeText(
156 | this,
157 | getString(R.string.messageErrorSendToServer),
158 | Toast.LENGTH_LONG
159 | )
160 | .show()
161 | Log.i("server", "did not work $e")
162 | }
163 | }, Response.ErrorListener {
164 | Log.i("server", "Error $it")
165 | }) {
166 | override fun getParams(): Map {
167 | val params: MutableMap = HashMap()
168 | //Change with your post params
169 | params["sender"] = getString(R.string.serverPassword)
170 | params["data"] = jsonOrderedInvoice
171 | return params
172 | }
173 | }
174 | stringRequest.retryPolicy = DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS, 0, 1F)
175 | val requestQueue = Volley.newRequestQueue(this)
176 | requestQueue.add(stringRequest)
177 | }
178 |
179 | private fun goToShowOneInvoice() {
180 | val intent = Intent(this, ShowSingleInvoice::class.java)
181 | intent.putExtra("invoiceId", ordersInvoice.invoiceId)
182 | intent.putExtra("invoiceNote", ordersInvoice.invoiceNotes)
183 | intent.putExtra("invoiceSold", ordersInvoice.invoiceSold.toString())
184 | intent.putExtra(
185 | "netInvoiceValue",
186 | (ordersInvoice.invoiceTotalSum - ordersInvoice.invoiceSold).toString()
187 | )
188 | startActivity(intent)
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.content.DialogInterface
4 | import android.content.Intent
5 | import android.os.Bundle
6 | import androidx.appcompat.app.AlertDialog
7 | import androidx.appcompat.app.AppCompatActivity
8 | import kotlinx.android.synthetic.main.activity_main.*
9 | import java.text.DateFormat
10 | import java.text.SimpleDateFormat
11 | import java.util.*
12 |
13 |
14 | class MainActivity : AppCompatActivity() {
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | setContentView(R.layout.activity_main)
18 | getAndShowDate()
19 |
20 | enterMaterialProductButton.setOnClickListener {
21 | goToWoodProductsScreen()
22 | }
23 | showInvoicesButton.setOnClickListener { goToShowInvoices() }
24 | exitProgramButton.setOnClickListener { exitApp() }
25 | }
26 |
27 | private fun goToWoodProductsScreen() {
28 | val intent = Intent(this, WoodProducts::class.java)
29 | ordersInvoice = InvoiceObjectClass()
30 | orderedProduct = OrderedProduct()
31 | startActivity(intent)
32 | }
33 |
34 | override fun onBackPressed() {
35 | exitApp()
36 | }
37 |
38 | private fun exitApp() {
39 | showYesNoDialog()
40 | }
41 |
42 | private fun showYesNoDialog() {
43 | lateinit var dialog: AlertDialog
44 | val builder = AlertDialog.Builder(this)
45 | builder.setTitle(getString(R.string.finishTheAppTitle))
46 | builder.setMessage(getString(R.string.messageDoYouWantToFinishTheApp))
47 | val dialogClickListener = DialogInterface.OnClickListener { _, which ->
48 | when (which) {
49 | DialogInterface.BUTTON_POSITIVE -> this.finishAffinity()
50 | DialogInterface.BUTTON_NEGATIVE -> doNothing()
51 | }
52 | }
53 | builder.setPositiveButton(getString(R.string.yesAnswer), dialogClickListener)
54 | builder.setNegativeButton(getString(R.string.noAnswer), dialogClickListener)
55 | dialog = builder.create()
56 | dialog.show()
57 | }
58 |
59 | private fun goToShowInvoices() {
60 | val intent = Intent(this, ShowInvoices::class.java)
61 | startActivity(intent)
62 | }
63 |
64 | private fun getAndShowDate() {
65 | val calender = Calendar.getInstance().time
66 | val formatter = SimpleDateFormat.getDateInstance(DateFormat.MEDIUM, Locale.GERMAN)
67 | actualDate.text = formatter.format(calender)
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/QuantityAndPrice.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.content.DialogInterface
4 | import android.content.Intent
5 | import androidx.appcompat.app.AppCompatActivity
6 | import android.os.Bundle
7 | import android.text.Editable
8 | import android.text.InputType
9 | import android.text.TextWatcher
10 | import android.widget.Toast
11 | import androidx.appcompat.app.AlertDialog
12 | import kotlinx.android.synthetic.main.activity_quantity_and_price.*
13 | import java.lang.Exception
14 | import kotlin.math.round
15 |
16 | class QuantityAndPrice : AppCompatActivity() {
17 |
18 | override fun onCreate(savedInstanceState: Bundle?) {
19 | super.onCreate(savedInstanceState)
20 | setContentView(R.layout.activity_quantity_and_price)
21 |
22 | totalAmountInput?.setText(orderedProduct.numberOfUnits.toString())
23 | unitPriceInput?.setText(orderedProduct.unitPrice.toString())
24 |
25 | if (orderedProduct.productLength * orderedProduct.productThickness * orderedProduct.productWidth < 1e-5 &&
26 | orderedProduct.productType == ProductType.Sawnwood.toString()
27 | ) {
28 | totalAmountLabel.text = getString(R.string.totalVolumeText)
29 | totalAmountInput.inputType = unitPriceInput.inputType
30 | } else {
31 | totalAmountLabel.text = getString(R.string.totalNumberText)
32 | totalAmountInput.inputType = InputType.TYPE_CLASS_NUMBER
33 | }
34 |
35 | totalAmountInput.addTextChangedListener(object : TextWatcher {
36 | override fun afterTextChanged(s: Editable) {}
37 | override fun beforeTextChanged(
38 | s: CharSequence, start: Int,
39 | count: Int, after: Int
40 | ) {
41 | }
42 |
43 | override fun onTextChanged(
44 | s: CharSequence, start: Int,
45 | before: Int, count: Int
46 | ) {
47 | val totalVolume = round(calculateVolume() * 10e+5) / 10e+5
48 | totalVolumeoutput.text = totalVolume.toString()
49 |
50 | if (unitPriceInput.text.isNotEmpty()) {
51 | val totalPrice = round(calculateTotalPrice() * 100) / 100
52 | totalPriceOutput.text = decimalFormatChanger.format(totalPrice).toString()
53 | }
54 | }
55 | })
56 |
57 |
58 | unitPriceInput.addTextChangedListener(object : TextWatcher {
59 | override fun afterTextChanged(s: Editable) {}
60 | override fun beforeTextChanged(
61 | s: CharSequence, start: Int,
62 | count: Int, after: Int
63 | ) {
64 | }
65 |
66 | override fun onTextChanged(
67 | s: CharSequence, start: Int,
68 | before: Int, count: Int
69 | ) {
70 | if (s.isNotEmpty()) {
71 | val totalPrice = round(calculateTotalPrice() * 100) / 100
72 | totalPriceOutput.text = decimalFormatChanger.format(totalPrice).toString()
73 | }
74 | }
75 | })
76 | backButton.setOnClickListener { goToWoodProductsScreen() }
77 | addToInvoiceButton.setOnClickListener { goToInvoiceReviewScreen() }
78 | cancelInvoiceButton.setOnClickListener { resetInvoiceYesNoDialog() }
79 | }
80 |
81 | private fun goToInvoiceReviewScreen() {
82 | if (unitPriceInput.text.isNotEmpty() && totalAmountInput.text.isNotEmpty()) {
83 | assignDataToOrderedProduct()
84 | ordersInvoice.orderedProductList.add(orderedProduct)
85 | val intent = Intent(this, InvoiceReviewScreen::class.java)
86 | startActivity(intent)
87 | } else {
88 | Toast.makeText(
89 | this,
90 | getString(R.string.errorMessageNoAmountAndUnitPrice),
91 | Toast.LENGTH_SHORT
92 | ).show()
93 | }
94 |
95 | }
96 |
97 | private fun assignDataToOrderedProduct() {
98 | assignValuesToOrderedProduct()
99 | var totalPrice = 0.0
100 | if (orderedProduct.productType == ProductType.Sawnwood.toString()) {
101 | val totalVolume = calculateVolume()
102 | orderedProduct.totalVolume = round(totalVolume * 10e+5) / 10e+5
103 | totalPrice = orderedProduct.unitPrice * totalVolume
104 | }
105 | if (orderedProduct.productType == ProductType.Plywood.toString()) {
106 | totalPrice = orderedProduct.unitPrice * orderedProduct.numberOfUnits
107 | }
108 | orderedProduct.totalPrice = round(totalPrice * 100) / 100
109 | }
110 |
111 | fun calculateVolume(): Double {
112 | val totalAmount = try {
113 | totalAmountInput.text.toString().toInt()
114 | } catch (e: Exception) {
115 | 0
116 | }
117 |
118 | var totalVolume = 0.0
119 | if (orderedProduct.productType == ProductType.Sawnwood.toString()) {
120 | totalVolume =
121 | totalAmount * orderedProduct.productLength * orderedProduct.productWidth * orderedProduct.productThickness
122 | }
123 |
124 | if (orderedProduct.productLength * orderedProduct.productWidth * orderedProduct.productThickness < 1e-5 &&
125 | orderedProduct.productType == ProductType.Sawnwood.toString()
126 | ) {
127 | totalVolume = try {
128 | totalAmountInput.text.toString().toDouble()
129 | } catch (e: Exception) {
130 | 0.0
131 | }
132 |
133 | }
134 | return totalVolume
135 | }
136 |
137 | fun calculateTotalPrice(): Double {
138 | var totalPrice = 0.0
139 | assignValuesToOrderedProduct()
140 |
141 | if (orderedProduct.productType == ProductType.Sawnwood.toString()) {
142 | val totalVolume = calculateVolume()
143 | orderedProduct.totalVolume = totalVolume
144 | totalPrice = orderedProduct.unitPrice * totalVolume
145 | }
146 | if (orderedProduct.productType == ProductType.Plywood.toString()) {
147 | totalPrice = orderedProduct.unitPrice * orderedProduct.numberOfUnits
148 | }
149 | return totalPrice
150 | }
151 |
152 | private fun assignValuesToOrderedProduct() {
153 | try {
154 | orderedProduct.unitPrice = unitPriceInput.text.toString().toDouble()
155 | } catch (e: Exception) {
156 | orderedProduct.unitPrice = 0.0
157 | }
158 |
159 | try {
160 | orderedProduct.numberOfUnits = totalAmountInput.text.toString().toInt()
161 | } catch (e: Exception) {
162 | orderedProduct.numberOfUnits = 0
163 | }
164 | }
165 |
166 | override fun onBackPressed() {
167 | goToWoodProductsScreen()
168 | }
169 |
170 | private fun goToWoodProductsScreen() {
171 | val intent = Intent(this, WoodProducts::class.java)
172 | startActivity(intent)
173 | }
174 |
175 | private fun cancelInvoice() {
176 | ordersInvoice = InvoiceObjectClass()
177 | orderedProduct = OrderedProduct()
178 | val intent = Intent(this, MainActivity::class.java)
179 | startActivity(intent)
180 | }
181 |
182 | private fun resetInvoiceYesNoDialog() {
183 | lateinit var dialog: AlertDialog
184 | val builder = AlertDialog.Builder(this)
185 | builder.setTitle(getString(R.string.cancelInvoiceMessageTitle))
186 | builder.setMessage(getString(R.string.doYouWantToCancelInvoiceMessage))
187 | val dialogClickListener = DialogInterface.OnClickListener { _, which ->
188 | when (which) {
189 | DialogInterface.BUTTON_POSITIVE -> cancelInvoice()
190 | DialogInterface.BUTTON_NEGATIVE -> doNothing()
191 | }
192 | }
193 | builder.setPositiveButton(getString(R.string.yesAnswer), dialogClickListener)
194 | builder.setNegativeButton(getString(R.string.noAnswer), dialogClickListener)
195 | dialog = builder.create()
196 | dialog.show()
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/SendToServer.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.widget.Toast
7 | import androidx.databinding.DataBindingUtil
8 | import androidx.lifecycle.Observer
9 | import androidx.lifecycle.ViewModelProviders
10 | import com.android.volley.DefaultRetryPolicy
11 | import com.android.volley.Request
12 | import com.android.volley.Response
13 | import com.android.volley.toolbox.StringRequest
14 | import com.android.volley.toolbox.Volley
15 | import com.example.woodinvoicetest.databinding.ActivitySendToServerBinding
16 | import com.google.gson.Gson
17 | import kotlinx.android.synthetic.main.activity_send_to_server.*
18 | import java.lang.Exception
19 |
20 | class SendToServer : AppCompatActivity() {
21 |
22 | override fun onCreate(savedInstanceState: Bundle?) {
23 | super.onCreate(savedInstanceState)
24 | val binding: ActivitySendToServerBinding =
25 | DataBindingUtil.setContentView(this, R.layout.activity_send_to_server)
26 |
27 | val application = requireNotNull(this).application
28 | val dataSource = WoodInvoicesDatabase.getInstance(application).woodInvoiceDao
29 | val woodInvoicesViewModelFactory = WoodInvoicesViewModelFactory(dataSource, application)
30 | val woodInvoicesViewModel = ViewModelProviders.of(this, woodInvoicesViewModelFactory)
31 | .get(WoodInvoicesViewModel::class.java)
32 | binding.lifecycleOwner = this
33 | binding.woodInvoicesViewModel = woodInvoicesViewModel
34 |
35 | val invoicesList = intent.getStringArrayListExtra("invoicesList")
36 |
37 | val invoicesMap: MutableMap = HashMap()
38 | val productsMap: MutableMap> = HashMap()
39 |
40 | if (invoicesList != null) {
41 | for (invoiceId in invoicesList) {
42 | val myLiveDAtaObserver = Observer { invoiceById ->
43 |
44 | val toSendInvoice = InvoiceObjectClass(
45 | invoiceId = invoiceById.invoiceId,
46 | customerName = invoiceById.customerName,
47 | invoiceTotalSum = invoiceById.totalSum,
48 | invoiceSold = invoiceById.invoiceSold,
49 | invoiceNotes = invoiceById.invoiceNotes
50 | )
51 | invoicesMap[invoiceById.invoiceId] = toSendInvoice
52 | }
53 | woodInvoicesViewModel.getInvoicesById(invoiceId).observe(this, myLiveDAtaObserver)
54 | }
55 |
56 | for (invoiceId in invoicesList) {
57 | val productsObserver = Observer> { productsList ->
58 | val productsListGathers: ArrayList = ArrayList()
59 | for (orderedProductI in productsList.indices) {
60 | val productI = productsList[orderedProductI]
61 | val toSendProduct = OrderedProduct(
62 | productId = productI.productId,
63 | productName = productI.productName,
64 | productType = productI.productType,
65 | marketProductName = productI.marketProductName,
66 | productThickness = productI.productThickness,
67 | productWidth = productI.productWidth,
68 | productLength = productI.productLength,
69 | productProperty1 = productI.productProperty1,
70 | productProperty2 = productI.productProperty2,
71 | productProperty3 = productI.productProperty3,
72 | numberOfUnits = productI.numberOfUnits,
73 | totalVolume = productI.totalVolume,
74 | unitPrice = productI.unitPrice,
75 | totalPrice = productI.totalPrice
76 | )
77 | productsListGathers.add(toSendProduct)
78 | productsMap[productI.invoiceId] = productsListGathers
79 | }
80 | }
81 | woodInvoicesViewModel.getProducts(invoiceId).observe(this, productsObserver)
82 | }
83 | sendButton.setOnClickListener {
84 | var counterI = 0
85 | for (invoiceId in invoicesList) {
86 | if (productsMap[invoiceId] != null) {
87 | for (orderedProductI in productsMap[invoiceId]!!) {
88 | invoicesMap[invoiceId]?.orderedProductList?.add(orderedProductI)
89 | }
90 | }
91 | val jsonOrderedInvoice = invoicesMap[invoiceId]?.let { it1 ->
92 | dataClassToJson(
93 | it1
94 | )
95 | }
96 | if (jsonOrderedInvoice != null) {
97 | sendInvoiceToServer(jsonOrderedInvoice)
98 | }
99 | counterI += 1
100 | determinateBar.progress = 100 * counterI / invoicesList.size
101 | }
102 | }
103 | }
104 | }
105 |
106 | private fun dataClassToJson(toSendInvoice: InvoiceObjectClass): String {
107 | val gson = Gson()
108 | return gson.toJson(toSendInvoice)
109 | }
110 |
111 | private fun sendInvoiceToServer(jsonOrderedInvoice: String) {
112 | val externalURL = getString(R.string.externalServerUrl)
113 | val internalURL = getString(R.string.internalServerUrl)
114 | val stringRequest: StringRequest = object : StringRequest(Request.Method.POST, internalURL,
115 | Response.Listener { response ->
116 | try {
117 | Log.i(
118 | "server",
119 | "the invoice was sent to the server and the response is $response"
120 | )
121 | Toast.makeText(
122 | this,
123 | getString(R.string.messageConfirmSentToServer),
124 | Toast.LENGTH_LONG
125 | )
126 | .show()
127 | } catch (e: Exception) {
128 | Toast.makeText(
129 | this,
130 | getString(R.string.messageErrorSendToServer),
131 | Toast.LENGTH_LONG
132 | )
133 | .show()
134 | Log.i("server", "did not work $e")
135 | }
136 | }, Response.ErrorListener {
137 | Log.i("server", "Error $it")
138 | }) {
139 | override fun getParams(): Map {
140 | val params: MutableMap = HashMap()
141 | //Change with your post params
142 | params["sender"] = getString(R.string.serverPassword)
143 | params["data"] = jsonOrderedInvoice
144 | return params
145 | }
146 | }
147 | stringRequest.retryPolicy = DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS, 0, 1F)
148 | val requestQueue = Volley.newRequestQueue(this)
149 | requestQueue.add(stringRequest)
150 | }
151 | }
152 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/ShowInvoices.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.DatePickerDialog
5 | import android.content.Intent
6 | import android.os.Bundle
7 | import android.util.Log
8 | import android.widget.LinearLayout
9 | import android.widget.TableRow
10 | import android.widget.TextView
11 | import android.widget.Toast
12 | import androidx.appcompat.app.AppCompatActivity
13 | import androidx.databinding.DataBindingUtil
14 | import androidx.lifecycle.Observer
15 | import androidx.lifecycle.ViewModelProviders
16 | import com.example.woodinvoicetest.databinding.ActivityShowInvoicesBinding
17 | import kotlinx.android.synthetic.main.activity_invoice_review_screen.invoiceTable
18 | import kotlinx.android.synthetic.main.activity_show_invoices.*
19 | import java.text.SimpleDateFormat
20 | import java.util.*
21 | import kotlin.collections.ArrayList
22 |
23 |
24 | class ShowInvoices : AppCompatActivity() {
25 | var rowsList: ArrayList = ArrayList()
26 | val formatter = SimpleDateFormat("dd.MM.yyyy")
27 | var invoicesSum: Double = 0.0
28 |
29 | override fun onCreate(savedInstanceState: Bundle?) {
30 | super.onCreate(savedInstanceState)
31 | val binding: ActivityShowInvoicesBinding =
32 | DataBindingUtil.setContentView(this, R.layout.activity_show_invoices)
33 |
34 | showColumnsTitles()
35 | initiateDate()
36 |
37 | val application = requireNotNull(this).application
38 | val dataSource = WoodInvoicesDatabase.getInstance(application).woodInvoiceDao
39 | val woodInvoicesViewModelFactory = WoodInvoicesViewModelFactory(dataSource, application)
40 | val woodInvoicesViewModel = ViewModelProviders.of(this, woodInvoicesViewModelFactory)
41 | .get(WoodInvoicesViewModel::class.java)
42 | binding.lifecycleOwner = this
43 | binding.woodInvoicesViewModel = woodInvoicesViewModel
44 | val myLiveDAtaObserver = Observer> { InvoiceList ->
45 | val invoicesList: ArrayList = ArrayList()
46 | var counterI = 0
47 | invoicesSum = 0.0
48 | for (invoiceI in InvoiceList) {
49 |
50 | val row = TableRow(this)
51 | row.gravity = 1
52 | row.layoutParams = LinearLayout.LayoutParams(
53 | LinearLayout.LayoutParams.MATCH_PARENT,
54 | LinearLayout.LayoutParams.WRAP_CONTENT
55 | )
56 | val netInvoiceValue = invoiceI.totalSum - invoiceI.invoiceSold
57 |
58 | var invoiceText = counterI.toString()
59 | createTextView(row, invoiceText)
60 | invoiceText = invoiceI.customerName
61 | createTextView(row, invoiceText)
62 | invoiceText = invoiceI.nameOfProducts
63 | createTextView(row, invoiceText)
64 | invoiceText =
65 | """${decimalFormatChanger.format(netInvoiceValue)} ${getString(R.string.currencyUnitText)} """
66 | createTextView(row, invoiceText)
67 |
68 | invoicesSum += netInvoiceValue
69 | counterI += 1
70 | invoiceTable.addView(row)
71 | rowsList.add(row)
72 | invoicesList.add(invoiceI.invoiceId)
73 | }
74 | invoicesSumTextView.text = decimalFormatChanger.format(invoicesSum).toString()
75 | for (i in rowsList.indices) {
76 | rowsList[i].setOnClickListener { showInvoice(InvoiceList[i], i) }
77 | }
78 | sendInvoicestoServer.setOnClickListener { goToSendToServer(invoicesList) }
79 |
80 | }
81 | startChosenDateTextView.setOnClickListener { chooseDatesDialog(startChosenDateTextView) }
82 | endChosenDateTextView.setOnClickListener { chooseDatesDialog(endChosenDateTextView) }
83 |
84 | showInvoiceButton.setOnClickListener {
85 | showInvoicesFunction(
86 | woodInvoicesViewModel,
87 | myLiveDAtaObserver
88 | )
89 | }
90 | }
91 |
92 | fun goToSendToServer(invoicesList: ArrayList) {
93 | val intent = Intent(this, SendToServer::class.java)
94 | intent.putStringArrayListExtra("invoicesList", invoicesList)
95 | startActivity(intent)
96 | }
97 |
98 | private fun showInvoicesFunction(
99 | woodInvoicesViewModel: WoodInvoicesViewModel,
100 | myLiveDAtaObserver: Observer>
101 | ) {
102 | val startChosenDate = formatter.parse(startChosenDateTextView.text.toString()).time
103 | val endChosenDate = formatter.parse(endChosenDateTextView.text.toString()).time
104 |
105 | if (rowsList.isNotEmpty()) {
106 | invoiceTable.removeAllViews()
107 | showColumnsTitles()
108 | }
109 |
110 |
111 | woodInvoicesViewModel.getInvoices(startChosenDate, endChosenDate)
112 | .observe(this, myLiveDAtaObserver)
113 | }
114 |
115 | private fun showInvoice(invoice: InvoicesTable, invoiceNumber: Int) {
116 | Toast.makeText(this, "Currency Nr. $invoiceNumber", Toast.LENGTH_SHORT).show()
117 | val netInvoiceValue = invoice.totalSum - invoice.invoiceSold
118 | goToShowOneInvoice(
119 | invoice.invoiceId,
120 | invoice.invoiceNotes,
121 | netInvoiceValue,
122 | invoice.invoiceSold
123 | )
124 | }
125 |
126 | private fun createTableColumnsTitles(row: TableRow) {
127 |
128 | var invoiceText = " ${getString(R.string.idText)} "
129 | createTextView(row, invoiceText)
130 | invoiceText = " ${getString(R.string.customerName)} "
131 | createTextView(row, invoiceText)
132 | invoiceText = getString(R.string.Products)
133 | createTextView(row, invoiceText)
134 | invoiceText = " ${getString(R.string.totalPriceText)} "
135 | createTextView(row, invoiceText)
136 | }
137 |
138 | fun showColumnsTitles() {
139 | val firstRow = TableRow(this)
140 | createTableColumnsTitles(firstRow)
141 | invoiceTable.addView(firstRow)
142 | }
143 |
144 | fun createTextView(row: TableRow, invoiceText: String) {
145 | val textView: TextView = TextView(this)
146 | textView.apply {
147 | layoutParams = TableRow.LayoutParams(
148 | TableRow.LayoutParams.WRAP_CONTENT,
149 | TableRow.LayoutParams.WRAP_CONTENT
150 | )
151 |
152 | text = invoiceText
153 | gravity = 1
154 | textSize = 16F
155 |
156 | }
157 | textView.margin(0F, 5F, 0F, 5F)
158 |
159 | row.addView(textView)
160 | }
161 |
162 | fun goToShowOneInvoice(
163 | invoiceId: String, invoiceNotes: String,
164 | netInvoiceValue: Double, invoiceSold: Double
165 | ) {
166 | val intent = Intent(this, ShowSingleInvoice::class.java)
167 | intent.putExtra("invoiceId", invoiceId)
168 | intent.putExtra("invoiceNote", invoiceNotes)
169 | intent.putExtra("invoiceSold", invoiceSold.toString())
170 | intent.putExtra("netInvoiceValue", netInvoiceValue.toString())
171 | startActivity(intent)
172 | }
173 |
174 | @SuppressLint("SetTextI18n")
175 | fun chooseDatesDialog(vText: TextView) {
176 | val calender = Calendar.getInstance()
177 | val currentYear = calender.get(Calendar.YEAR)
178 | val currentMonth = calender.get(Calendar.MONTH)
179 | val currentDay = calender.get(Calendar.DAY_OF_MONTH)
180 | val dpd = DatePickerDialog(
181 | this,
182 | DatePickerDialog.OnDateSetListener { view, year, monthOfYear, dayOfMonth ->
183 | val correctedMonth = monthOfYear + 1
184 | vText.text =
185 | formatter.format(formatter.parse("$dayOfMonth.$correctedMonth.$year"))
186 | .toString()
187 | },
188 | currentYear,
189 | currentMonth,
190 | currentDay
191 | )
192 | dpd.show()
193 | }
194 |
195 | fun initiateDate() {
196 | val calender = Calendar.getInstance()
197 | val currentYear = calender.get(Calendar.YEAR)
198 | var currentMonth = calender.get(Calendar.MONTH)
199 | var currentDay = calender.get(Calendar.DAY_OF_MONTH)
200 | currentMonth += 1
201 | startChosenDateTextView.text =
202 | formatter.format(formatter.parse("$currentDay.$currentMonth.$currentYear"))
203 | currentDay += 1
204 | endChosenDateTextView.text =
205 | formatter.format(formatter.parse("$currentDay.$currentMonth.$currentYear"))
206 |
207 | }
208 |
209 | }
210 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/ShowSingleInvoice.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.annotation.SuppressLint
4 | import androidx.appcompat.app.AppCompatActivity
5 | import android.os.Bundle
6 | import android.widget.TableRow
7 | import android.widget.TextView
8 | import androidx.databinding.DataBindingUtil
9 | import androidx.lifecycle.Observer
10 | import androidx.lifecycle.ViewModelProviders
11 | import com.example.woodinvoicetest.databinding.ActivityShowSingleInvoiceBinding
12 | import kotlinx.android.synthetic.main.activity_show_single_invoice.*
13 |
14 | class ShowSingleInvoice : AppCompatActivity() {
15 |
16 | @SuppressLint("SetTextI18n")
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | val binding: ActivityShowSingleInvoiceBinding =
20 | DataBindingUtil.setContentView(this, R.layout.activity_show_single_invoice)
21 | val invoiceNumber = intent.getStringExtra("invoiceId")
22 | val invoiceNotes = intent.getStringExtra("invoiceNote")
23 | val invoiceSold = intent.getStringExtra("invoiceSold")
24 | val netInvoiceValue = intent.getStringExtra("netInvoiceValue")
25 |
26 | val application = requireNotNull(this).application
27 | val dataSource = WoodInvoicesDatabase.getInstance(application).woodInvoiceDao
28 | val woodInvoicesViewModelFactory = WoodInvoicesViewModelFactory(dataSource, application)
29 | val woodInvoicesViewModel = ViewModelProviders.of(this, woodInvoicesViewModelFactory)
30 | .get(WoodInvoicesViewModel::class.java)
31 | binding.lifecycleOwner = this
32 | binding.woodInvoicesViewModel = woodInvoicesViewModel
33 |
34 | var invoiceTotalSum = 0.0
35 | val firstRow = TableRow(this)
36 | createTableColumnsTitles(firstRow)
37 | invoiceTable.addView(firstRow)
38 |
39 | val myLiveDAtaObserver = Observer> { productsList ->
40 |
41 | for (orderedProductI in productsList.indices) {
42 | val productI = productsList[orderedProductI]
43 | val row = TableRow(this)
44 | val productNumber = orderedProductI + 1
45 |
46 | showOneProduct(productI, row, productNumber)
47 | invoiceTable.addView(row)
48 | invoiceTotalSum += productI.totalPrice
49 | }
50 | totalPrice.text = decimalFormatChanger.format(invoiceTotalSum).toString()
51 | }
52 | if (invoiceNumber != null) {
53 | woodInvoicesViewModel.getProducts(invoiceNumber).observe(this, myLiveDAtaObserver)
54 | invoiceNumberTextview.text =
55 | """${getString(R.string.invoiceNumberPlaceHolder)} $invoiceNumber"""
56 |
57 | invoiceNoteText.text = invoiceNotes
58 | soldValueText.text = invoiceSold
59 | netValueText.text = decimalFormatChanger.format(netInvoiceValue.toDouble()).toString()
60 | }
61 |
62 | }
63 |
64 | private fun createTableColumnsTitles(row: TableRow) {
65 |
66 | var invoiceText = getString(R.string.idText)
67 | createTextView(row, invoiceText)
68 | invoiceText = getString(R.string.propertiesLabelText)
69 | createTextView(row, invoiceText)
70 | invoiceText = getString(R.string.totalNumberShortText)
71 | createTextView(row, invoiceText)
72 | invoiceText = getString(R.string.totalVolumeShortText)
73 | createTextView(row, invoiceText)
74 | invoiceText = getString(R.string.unitPriceText)
75 | createTextView(row, invoiceText)
76 | invoiceText = getString(R.string.totalPriceText)
77 | createTextView(row, invoiceText)
78 | }
79 |
80 | private fun createTextView(row: TableRow, invoiceText: String) {
81 | val textView: TextView = TextView(this)
82 | textView.apply {
83 | layoutParams = TableRow.LayoutParams(
84 | TableRow.LayoutParams.WRAP_CONTENT,
85 | TableRow.LayoutParams.WRAP_CONTENT
86 | )
87 | text = invoiceText
88 | textSize = 16F
89 | gravity = 1
90 | }
91 | textView.margin(2F, 2F, 2F, 2F)
92 | row.addView(textView)
93 | }
94 |
95 | private fun showOneProduct(productI: ProductsTable, row: TableRow, productNumber: Int) {
96 | var invoiceText = if (productNumber < 10) {
97 | " 00$productNumber "
98 | } else {
99 | " 0$productNumber "
100 | }
101 | createTextView(row, invoiceText)
102 | invoiceText = productI.marketProductName
103 |
104 | if (productI.productWidth > 0.0) {
105 | invoiceText += """ ${getString(R.string.widthText)} ${(productI.productWidth * 100)} ${getString(
106 | R.string.cm
107 | )} """
108 | }
109 |
110 | if (productI.productThickness > 0.0) {
111 | invoiceText += """ ${getString(R.string.thicknessText)} ${(productI.productThickness * 1000)} ${getString(
112 | R.string.mm
113 | )} """
114 | }
115 |
116 | if (productI.productLength > 0.0) {
117 | invoiceText += """ ${getString(R.string.lengthText)} ${productI.productLength} ${getString(
118 | R.string.m
119 | )} """
120 | }
121 |
122 | if (productI.productProperty1.isNotEmpty()) {
123 | invoiceText += """ ${productI.productProperty1} """
124 | }
125 | if (productI.productProperty2.isNotEmpty()) {
126 | invoiceText += """ ${productI.productProperty2} """
127 | }
128 | if (productI.productProperty3.isNotEmpty()) {
129 | invoiceText += """ ${productI.productProperty3} """
130 | }
131 | createTextView(row, invoiceText)
132 | invoiceText = if (productI.numberOfUnits > 0) {
133 | """ ${productI.numberOfUnits} """
134 | } else {
135 | """ ${getString(R.string.notGivenText)} """
136 | }
137 | createTextView(row, invoiceText)
138 |
139 | if (productI.productType == ProductType.Sawnwood.toString()) {
140 | invoiceText = """${productI.totalVolume} ${getString(R.string.m3Unit)} """
141 | createTextView(row, invoiceText)
142 | }
143 | if (productI.productType == ProductType.Plywood.toString()) {
144 | invoiceText = """ ${getString(R.string.notGivenText)} """
145 | createTextView(row, invoiceText)
146 | }
147 | invoiceText =
148 | """${decimalFormatChanger.format(productI.unitPrice)} ${getString(R.string.currencyUnitText)} """
149 | createTextView(row, invoiceText)
150 | invoiceText =
151 | """${decimalFormatChanger.format(productI.totalPrice)} ${getString(R.string.currencyUnitText)} """
152 | createTextView(row, invoiceText)
153 | }
154 |
155 | }
156 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/WoodInvoicesDao.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.room.Dao
5 | import androidx.room.Insert
6 | import androidx.room.Query
7 | import java.util.*
8 |
9 | @Dao
10 | interface WoodInvoicesDao {
11 | @Insert
12 | fun insert(invoice: InvoicesTable)
13 |
14 | @Insert
15 | fun insertProduct(product: ProductsTable)
16 |
17 | @Query("SELECT * FROM invoices_table WHERE Not deleted AND invoiceDate>=:startChosenDate AND invoiceDate<=:endChosenDate")
18 | fun getAllInvoices(startChosenDate: Long, endChosenDate: Long): LiveData>
19 |
20 | @Query("SELECT * FROM invoices_table WHERE Not deleted AND InvoiceId = :invoiceId")
21 | fun getAllInvoicesById(invoiceId: String): LiveData
22 |
23 | @Query("SELECT * FROM products_table WHERE invoiceId=:invoiceNumber")
24 | fun getProducts(invoiceNumber: String): LiveData>
25 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/WoodInvoicesDatabase.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.content.Context
4 | import androidx.room.Database
5 | import androidx.room.Room
6 | import androidx.room.RoomDatabase
7 |
8 | @Database(entities = [InvoicesTable::class, ProductsTable::class], version = 6, exportSchema = false)
9 | abstract class WoodInvoicesDatabase : RoomDatabase() {
10 | abstract val woodInvoiceDao: WoodInvoicesDao
11 |
12 | companion object {
13 |
14 | @Volatile
15 | private var INSTANCE: WoodInvoicesDatabase? = null
16 |
17 | fun getInstance(context: Context): WoodInvoicesDatabase {
18 | synchronized(this) {
19 | var instance = INSTANCE
20 |
21 | if (instance == null) {
22 | instance = Room.databaseBuilder(
23 | context.applicationContext,
24 | WoodInvoicesDatabase::class.java,
25 | "wood_invoices_database"
26 | )
27 | .fallbackToDestructiveMigration()
28 | .build()
29 | INSTANCE = instance
30 | }
31 | return instance
32 | }
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/WoodInvoicesRepository.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import androidx.lifecycle.LiveData
4 |
5 | class WoodInvoicesRepository (private val woodInvoicesDao: WoodInvoicesDao) {
6 |
7 | // Room executes all queries on a separate thread.
8 | // Observed LiveData will notify the observer when the data has changed.
9 | val allInvoices: LiveData> = woodInvoicesDao.getAllInvoices(0,0)
10 |
11 | suspend fun insert(invoice: InvoicesTable) {
12 | woodInvoicesDao.insert(invoice)
13 | }
14 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/WoodInvoicesViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.app.Application
4 | import android.util.Log
5 | import androidx.lifecycle.AndroidViewModel
6 | import androidx.lifecycle.LiveData
7 | import kotlinx.coroutines.*
8 |
9 |
10 | class WoodInvoicesViewModel(
11 | val database: WoodInvoicesDao,
12 | application: Application
13 | ) : AndroidViewModel(application) {
14 | private val viewModelJob = Job()
15 |
16 | override fun onCleared() {
17 | super.onCleared()
18 | viewModelJob.cancel()
19 | }
20 |
21 | private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)
22 | fun getInvoices(startChosenDate: Long, endChosenDate: Long): LiveData> {
23 | return database.getAllInvoices(startChosenDate, endChosenDate)
24 | }
25 |
26 | fun getInvoicesById(invoiceID: String): LiveData {
27 | return database.getAllInvoicesById(invoiceID)
28 | }
29 |
30 | fun getProducts(invoiceNumber: String): LiveData> {
31 | return database.getProducts(invoiceNumber)
32 | }
33 |
34 |
35 | fun getNamesOfOrderedProducts(): String {
36 | var nameOfOrderedProducts = ""
37 | for (productI in ordersInvoice.orderedProductList) {
38 | nameOfOrderedProducts += " " + productI.marketProductName + " "
39 | }
40 | return nameOfOrderedProducts
41 | }
42 |
43 | fun onConfirmEverything() {
44 | uiScope.launch {
45 | val nameOfOrderedProducts = getNamesOfOrderedProducts()
46 | val newInvoice = InvoicesTable(
47 | invoiceId = ordersInvoice.invoiceId,
48 | customerName = ordersInvoice.customerName,
49 | nameOfProducts = nameOfOrderedProducts,
50 | totalSum = ordersInvoice.invoiceTotalSum,
51 | invoiceSold = ordersInvoice.invoiceSold,
52 | invoiceNotes = ordersInvoice.invoiceNotes
53 | )
54 | Log.i("livedata", "insert invoice data: $newInvoice")
55 | insert(newInvoice)
56 |
57 | for (productI in ordersInvoice.orderedProductList) {
58 | val newProduct = ProductsTable(
59 | invoiceId = ordersInvoice.invoiceId,
60 | productId = productI.productId,
61 | productName = productI.productName.toString(),
62 | marketProductName = productI.marketProductName,
63 | productType = productI.productType.toString(),
64 | productThickness = productI.productThickness,
65 | productWidth = productI.productWidth,
66 | productLength = productI.productLength,
67 | productProperty1 = productI.productProperty1,
68 | productProperty2 = productI.productProperty2,
69 | productProperty3 = productI.productProperty3,
70 | numberOfUnits = productI.numberOfUnits,
71 | totalVolume = productI.totalVolume,
72 | unitPrice = productI.unitPrice,
73 | totalPrice = productI.totalPrice
74 | )
75 | Log.i("livedata", "insert product data: $productI")
76 | insertProduct(newProduct)
77 | }
78 |
79 | }
80 | }
81 |
82 | private suspend fun insert(newInvoice: InvoicesTable) {
83 | withContext(Dispatchers.IO) {
84 | database.insert(newInvoice)
85 | }
86 | }
87 |
88 | private suspend fun insertProduct(newProduct: ProductsTable) {
89 | withContext(Dispatchers.IO) {
90 | database.insertProduct(newProduct)
91 | }
92 | }
93 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/WoodInvoicesViewModelFactory.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.app.Application
4 | import androidx.lifecycle.ViewModel
5 | import androidx.lifecycle.ViewModelProvider
6 | import java.lang.IllegalArgumentException
7 |
8 | class WoodInvoicesViewModelFactory( private val dataSource: WoodInvoicesDao,
9 | private val application: Application): ViewModelProvider.Factory {
10 | @Suppress("unchecked_cast")
11 | override fun create(modelClass: Class): T {
12 | if(modelClass.isAssignableFrom(WoodInvoicesViewModel::class.java)){
13 | return WoodInvoicesViewModel(dataSource, application) as T
14 | }
15 | throw IllegalArgumentException("Unknown ViewModel Class")
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/woodinvoicetest/utils.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import android.content.Context
4 | import android.util.TypedValue
5 | import android.view.View
6 | import android.view.ViewGroup
7 |
8 | fun doNothing(){
9 |
10 | }
11 |
12 | fun View.margin(
13 | left: Float? = null,
14 | top: Float? = null,
15 | right: Float? = null,
16 | bottom: Float? = null
17 | ) {
18 | layoutParams {
19 | left?.run { leftMargin = dpToPx(this) }
20 | top?.run { topMargin = dpToPx(this) }
21 | right?.run { rightMargin = dpToPx(this) }
22 | bottom?.run { bottomMargin = dpToPx(this) }
23 | }
24 | }
25 |
26 | inline fun View.layoutParams(block: T.() -> Unit) {
27 | if (layoutParams is T) block(layoutParams as T)
28 | }
29 |
30 | fun View.dpToPx(dp: Float): Int = context.dpToPx(dp)
31 | fun Context.dpToPx(dp: Float): Int =
32 | TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics).toInt()
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/drawable/background.jpg
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
14 |
18 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/choose_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
15 |
19 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/my_cancel_button.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/my_delete_icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/my_edit_icon.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/subbackground.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/drawable/subbackground.jpg
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_add_customer_name.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
21 |
22 |
29 |
30 |
39 |
40 |
41 |
53 |
54 |
62 |
63 |
72 |
73 |
82 |
83 |
84 |
85 |
97 |
98 |
107 |
108 |
118 |
119 |
128 |
129 |
130 |
131 |
143 |
144 |
148 |
149 |
157 |
158 |
168 |
171 |
172 |
173 |
174 |
175 |
179 |
180 |
188 |
189 |
199 |
200 |
208 |
209 |
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_confirm_everything.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
18 |
19 |
20 |
32 |
33 |
46 |
47 |
48 |
57 |
58 |
67 |
68 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_invoice_review_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
32 |
33 |
42 |
43 |
52 |
53 |
54 |
55 |
63 |
64 |
73 |
74 |
83 |
84 |
93 |
94 |
95 |
96 |
104 |
105 |
109 |
110 |
113 |
114 |
118 |
119 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
23 |
24 |
31 |
32 |
39 |
40 |
41 |
52 |
53 |
59 |
60 |
66 |
67 |
73 |
74 |
75 |
76 |
85 |
86 |
93 |
94 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_quantity_and_price.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
32 |
33 |
41 |
42 |
50 |
51 |
52 |
63 |
64 |
68 |
69 |
76 |
77 |
88 |
89 |
90 |
91 |
95 |
96 |
103 |
104 |
112 |
113 |
120 |
121 |
122 |
123 |
127 |
128 |
135 |
136 |
146 |
147 |
148 |
149 |
153 |
154 |
155 |
162 |
163 |
171 |
172 |
179 |
180 |
181 |
182 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/activity_woodproducts.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
23 |
24 |
39 |
40 |
50 |
51 |
60 |
61 |
70 |
71 |
80 |
81 |
90 |
91 |
100 |
101 |
110 |
111 |
120 |
121 |
130 |
131 |
140 |
141 |
142 |
155 |
156 |
167 |
168 |
177 |
178 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/activity_add_customer_name.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
24 |
25 |
34 |
35 |
44 |
45 |
55 |
56 |
57 |
58 |
75 |
76 |
84 |
85 |
94 |
95 |
103 |
104 |
105 |
106 |
117 |
118 |
122 |
123 |
131 |
132 |
143 |
144 |
145 |
146 |
150 |
151 |
159 |
160 |
171 |
172 |
181 |
182 |
183 |
184 |
185 |
186 |
195 |
196 |
203 |
204 |
213 |
214 |
215 |
216 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/activity_confirm_everything.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
18 |
19 |
30 |
31 |
43 |
44 |
53 |
54 |
63 |
64 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/activity_invoice_review_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
33 |
34 |
44 |
45 |
55 |
56 |
57 |
58 |
67 |
68 |
77 |
78 |
87 |
88 |
96 |
97 |
98 |
99 |
108 |
109 |
114 |
115 |
119 |
120 |
125 |
126 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
23 |
24 |
31 |
32 |
39 |
40 |
41 |
52 |
53 |
59 |
60 |
66 |
67 |
73 |
74 |
75 |
76 |
87 |
88 |
95 |
96 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/activity_quantity_and_price.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
33 |
34 |
44 |
45 |
55 |
56 |
57 |
71 |
72 |
75 |
76 |
85 |
86 |
100 |
101 |
102 |
103 |
107 |
108 |
116 |
117 |
129 |
130 |
137 |
138 |
139 |
140 |
143 |
144 |
153 |
154 |
168 |
169 |
170 |
171 |
174 |
175 |
184 |
185 |
197 |
198 |
205 |
206 |
207 |
208 |
209 |
--------------------------------------------------------------------------------
/app/src/main/res/layout-sw600dp/activity_woodproducts.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
38 |
39 |
49 |
50 |
59 |
60 |
69 |
70 |
79 |
80 |
89 |
90 |
99 |
100 |
109 |
110 |
119 |
120 |
129 |
130 |
139 |
140 |
141 |
153 |
154 |
165 |
166 |
175 |
176 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_add_customer_name.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
23 |
24 |
31 |
32 |
39 |
40 |
47 |
48 |
49 |
50 |
63 |
64 |
68 |
69 |
76 |
77 |
87 |
88 |
91 |
92 |
93 |
94 |
98 |
99 |
106 |
107 |
117 |
118 |
126 |
127 |
128 |
129 |
130 |
131 |
142 |
143 |
152 |
153 |
163 |
164 |
173 |
174 |
175 |
176 |
185 |
186 |
193 |
194 |
204 |
205 |
206 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_confirm_everything.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
18 |
19 |
20 |
30 |
31 |
40 |
41 |
50 |
51 |
60 |
61 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_invoice_review_screen.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
26 |
27 |
33 |
34 |
40 |
41 |
47 |
48 |
49 |
50 |
60 |
61 |
70 |
71 |
80 |
81 |
90 |
91 |
92 |
93 |
100 |
101 |
105 |
106 |
110 |
111 |
115 |
116 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
26 |
27 |
36 |
37 |
46 |
47 |
53 |
54 |
60 |
61 |
67 |
68 |
69 |
70 |
79 |
80 |
88 |
89 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_quantity_and_price.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
23 |
24 |
32 |
33 |
41 |
42 |
51 |
52 |
53 |
63 |
64 |
69 |
70 |
77 |
78 |
88 |
89 |
90 |
91 |
96 |
97 |
105 |
106 |
115 |
116 |
124 |
125 |
126 |
127 |
132 |
133 |
140 |
141 |
151 |
152 |
153 |
154 |
159 |
160 |
167 |
168 |
176 |
177 |
184 |
185 |
186 |
187 |
188 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_send_to_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
18 |
19 |
20 |
31 |
32 |
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_show_invoices.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
18 |
19 |
27 |
28 |
33 |
34 |
38 |
39 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
73 |
74 |
82 |
83 |
91 |
92 |
93 |
94 |
100 |
101 |
109 |
110 |
118 |
119 |
120 |
121 |
130 |
131 |
141 |
142 |
143 |
153 |
154 |
162 |
163 |
171 |
172 |
180 |
181 |
182 |
183 |
184 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_woodproducts.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
23 |
24 |
40 |
41 |
51 |
52 |
61 |
62 |
71 |
72 |
81 |
82 |
91 |
92 |
101 |
102 |
111 |
112 |
121 |
122 |
131 |
132 |
141 |
142 |
143 |
156 |
157 |
168 |
169 |
178 |
179 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/alert_dialog_with_edittext.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/my_ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-hdpi/my_ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/my_ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-mdpi/my_ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/my_ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xhdpi/my_ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/my_ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xxhdpi/my_ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/my_ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/app/src/main/res/mipmap-xxxhdpi/my_ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #000000
4 | #000000
5 | #03DAC5
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 14sp
4 | 18sp
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Wood Orders Taker
3 | Deeb For Wood Trading
4 | Industrial Zone
5 | Wood Products List
6 | View Invoices
7 | Exit
8 | Back
9 | Button
10 | Choose a Product
11 | Add to the Invoice
12 | Back
13 | Cancel Invoice
14 | Total Number
15 | Number
16 | m3
17 | Total Volume
18 | Volume
19 | Unit Price
20 | \$
21 | Total Price
22 | 0.0
23 | Show Invoice
24 | Print Invoice
25 | DONE!!!
26 | Customer
27 | Discount
28 | e.g. Maher Deeb
29 | e.g. 5
30 | Invoice Value
31 | 350000
32 | Confirm Payment
33 | Pay
34 | Add a new product
35 | e.g. 15
36 | Payment confirmed
37 | The invoice was sent to the printer successfully
38 | http://xx.xxx.xx.xx:5000/data_api
39 | http://10.0.2.2:5000/data_api
40 | The invoice was sent to the server successfully
41 | Failed to send the invoice to the server
42 | Exit App
43 | Do you want to exit the App?
44 | Yes
45 | No
46 | Invoice Nr.
47 | 27.05.2020
48 | Select
49 | \t
50 | Cancel Invoice
51 | Do you want to cancel this invoice?
52 | Choose
53 | cm
54 | mm
55 | m
56 | Please enter the amount and the unit price
57 | Go back to the main screen
58 | Invoices from
59 | Show Invoices
60 | Invoices until
61 | Send invoices to the server
62 | Notes
63 | e.g. paid
64 | Net Sum
65 | Sum
66 | Send
67 | Enter
68 | Nr.
69 | Description
70 | Delete Product
71 | Do you want to delete this product
72 | .
73 | Thickness
74 | Length
75 | Width
76 | Please enter the customer\'s Name
77 | xxxxxxxxxxx
78 | Products"
79 |
80 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
21 |
22 |
27 |
28 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Your URL(ex: 127.0.0.1)
5 |
6 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/woodinvoicetest/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.woodinvoicetest
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | ext.kotlin_version = '1.3.72'
5 | ext.version_room = "2.0.0"
6 | ext.version_lifecycle_extensions = "2.0.0"
7 | ext.version_coroutine = "1.1.0"
8 | repositories {
9 | google()
10 | jcenter()
11 |
12 | }
13 | dependencies {
14 | classpath 'com.android.tools.build:gradle:3.6.3'
15 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
16 | classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
17 |
18 | // NOTE: Do not place your application dependencies here; they belong
19 | // in the individual module build.gradle files
20 | }
21 | }
22 |
23 | allprojects {
24 | repositories {
25 | google()
26 | jcenter()
27 |
28 | }
29 | }
30 |
31 | task clean(type: Delete) {
32 | delete rootProject.buildDir
33 | }
34 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MaherDeeb/take_orders_app/63bdf72166f5a0bcd50d90ea569880aea91d3e83/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed May 27 15:18:16 CEST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name='Wood Invoice Test'
2 | include ':app'
3 |
--------------------------------------------------------------------------------