diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000..ef68cc5
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,12 @@
+# These are supported funding model platforms
+
+github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
+patreon: # Replace with a single Patreon username
+open_collective: # Replace with a single Open Collective username
+ko_fi: # Replace with a single Ko-fi username
+tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
+community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
+liberapay: # Replace with a single Liberapay username
+issuehunt: # Replace with a single IssueHunt username
+otechie: # Replace with a single Otechie username
+custom: ['https://paypal.me/apozasker'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/README.md b/README.md
index d3b8a8b..8a5d032 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,7 @@ Every day Contact Diary will prompt you to insert the events you have attended a
- Configurable notification time, so the prompt does not interfere with your daily workflow.
- Show only potentially risky contacts.
- Automatic removal of entries older than 15 days.
+- Export your latest contacts to a CSV file that you can share with the authorities.
- JUST ONE PERMISSION, that needed for the app being able to notify you after device restarts. Nothing else.
- In particular, NO INTERNET permission. The information entered is yours, and it never leaves your device.
diff --git a/android_app/app/build.gradle b/android_app/app/build.gradle
index 58b5a15..fa873c4 100644
--- a/android_app/app/build.gradle
+++ b/android_app/app/build.gradle
@@ -4,16 +4,17 @@ apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
- buildToolsVersion "30.0.1"
+ buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.apozas.contactdiary"
minSdkVersion 14
targetSdkVersion 30
- versionCode 10
- versionName "1.1.4"
+ versionCode 12
+ versionName "1.3.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ multiDexEnabled true
}
applicationVariants.all { variant ->
@@ -46,14 +47,14 @@ android {
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.core:core-ktx:1.3.1'
+ implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
- implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
- implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
- implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
- implementation 'androidx.preference:preference:1.1.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+ implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1'
+ implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
implementation 'androidx.preference:preference-ktx:1.1.1'
+ implementation 'com.android.support:multidex:1.0.3'
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/PrivacyActivity.kt b/android_app/app/src/github/java/com/apozas/contactdiary/PrivacyActivity.kt
similarity index 100%
rename from android_app/app/src/main/java/com/apozas/contactdiary/PrivacyActivity.kt
rename to android_app/app/src/github/java/com/apozas/contactdiary/PrivacyActivity.kt
diff --git a/android_app/app/src/main/AndroidManifest.xml b/android_app/app/src/main/AndroidManifest.xml
index 62bfd8e..5d590d9 100644
--- a/android_app/app/src/main/AndroidManifest.xml
+++ b/android_app/app/src/main/AndroidManifest.xml
@@ -54,18 +54,29 @@
+ android:launchMode="singleTop"
+ android:screenOrientation="portrait" >
+ android:label="@string/privacy_title"
+ android:screenOrientation="portrait" >
+
+
+
+
+
+
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/ContactDatabase.kt b/android_app/app/src/main/java/com/apozas/contactdiary/ContactDatabase.kt
index f49c1b0..b064f43 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/ContactDatabase.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/ContactDatabase.kt
@@ -25,13 +25,16 @@ class ContactDatabase {
const val TYPE_COLUMN = "Type"
const val NAME_COLUMN = "Name"
const val PLACE_COLUMN = "Place"
- const val DATETIME_COLUMN = "Timestamp"
+ const val TIMESTAMP_COLUMN = "Timestamp"
+ const val DURATION_COLUMN = "Duration"
const val PHONE_COLUMN = "Phone"
const val RELATIVE_COLUMN = "Relative"
const val COMPANIONS_COLUMN = "Companions"
const val CLOSECONTACT_COLUMN = "CloseContact"
const val ENCOUNTER_COLUMN = "EncounterType"
const val NOTES_COLUMN = "Notes"
+ const val TIME_BEGIN_COLUMN = "BeginTime"
+ const val TIME_END_COLUMN = "EndTime"
}
}
@@ -42,7 +45,8 @@ class ContactDatabase {
"${ContactDatabase.FeedEntry.TYPE_COLUMN} TEXT," +
"${ContactDatabase.FeedEntry.NAME_COLUMN} TEXT," +
"${ContactDatabase.FeedEntry.PLACE_COLUMN} TEXT," +
- "${ContactDatabase.FeedEntry.DATETIME_COLUMN} INT," +
+ "${ContactDatabase.FeedEntry.TIME_BEGIN_COLUMN} INT," +
+ "${ContactDatabase.FeedEntry.TIME_END_COLUMN} INT," +
"${ContactDatabase.FeedEntry.PHONE_COLUMN} TEXT," +
"${ContactDatabase.FeedEntry.RELATIVE_COLUMN} TINYINT," +
"${ContactDatabase.FeedEntry.COMPANIONS_COLUMN} TEXT," +
@@ -52,5 +56,24 @@ class ContactDatabase {
const val SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS ${ContactDatabase.FeedEntry.TABLE_NAME}"
const val SQL_UPDATE_2 = "ALTER TABLE ${ContactDatabase.FeedEntry.TABLE_NAME} ADD COLUMN " +
"${ContactDatabase.FeedEntry.NOTES_COLUMN} TEXT"
+ const val SQL_UPDATE_3 = "ALTER TABLE ${ContactDatabase.FeedEntry.TABLE_NAME} ADD COLUMN " +
+ "${ContactDatabase.FeedEntry.DURATION_COLUMN} INT"
+ const val SQL_UPDATE_4_PART1 = "ALTER TABLE ${ContactDatabase.FeedEntry.TABLE_NAME} RENAME " +
+ "TO tmp_table"
+ const val SQL_UPDATE_4_PART2 = "INSERT INTO ${ContactDatabase.FeedEntry.TABLE_NAME}(" +
+ "${BaseColumns._ID}, ${ContactDatabase.FeedEntry.TYPE_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.NAME_COLUMN}, ${ContactDatabase.FeedEntry.PLACE_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.TIME_BEGIN_COLUMN}, ${ContactDatabase.FeedEntry.PHONE_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.RELATIVE_COLUMN}, ${ContactDatabase.FeedEntry.COMPANIONS_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.ENCOUNTER_COLUMN}, ${ContactDatabase.FeedEntry.CLOSECONTACT_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.NOTES_COLUMN}) " +
+ "SELECT ${BaseColumns._ID}, ${ContactDatabase.FeedEntry.TYPE_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.NAME_COLUMN}, ${ContactDatabase.FeedEntry.PLACE_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.TIMESTAMP_COLUMN}, ${ContactDatabase.FeedEntry.PHONE_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.RELATIVE_COLUMN}, ${ContactDatabase.FeedEntry.COMPANIONS_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.ENCOUNTER_COLUMN}, ${ContactDatabase.FeedEntry.CLOSECONTACT_COLUMN}, " +
+ "${ContactDatabase.FeedEntry.NOTES_COLUMN} " +
+ "FROM tmp_table"
+ const val SQL_UPDATE_4_PART3 = "DROP TABLE tmp_table"
}
}
\ No newline at end of file
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/DataCursorAdapter.kt b/android_app/app/src/main/java/com/apozas/contactdiary/DataCursorAdapter.kt
index c347fcd..f055209 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/DataCursorAdapter.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/DataCursorAdapter.kt
@@ -16,17 +16,19 @@ package com.apozas.contactdiary
*/
import android.content.Context
+import android.content.res.Configuration
import android.database.Cursor
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
+import androidx.appcompat.app.AppCompatDelegate
import androidx.cursoradapter.widget.CursorAdapter
import java.text.DateFormat
import java.util.*
class DataCursorAdapter(context: Context?, c: Cursor?) : CursorAdapter(context, c, 0) {
- private var mDateColumnIndex = cursor.getColumnIndex(ContactDatabase.ContactDatabase.FeedEntry.DATETIME_COLUMN)
+ private var mDateColumnIndex = cursor.getColumnIndex(ContactDatabase.ContactDatabase.FeedEntry.TIME_BEGIN_COLUMN)
private val formatter: DateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM)
private val inflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
@@ -38,7 +40,8 @@ class DataCursorAdapter(context: Context?, c: Cursor?) : CursorAdapter(context,
var contact = ""
if (cursor != null) {
contact = cursor.getString(
- cursor.getColumnIndex(ContactDatabase.ContactDatabase.FeedEntry.NAME_COLUMN))
+ cursor.getColumnIndex(ContactDatabase.ContactDatabase.FeedEntry.NAME_COLUMN)
+ )
}
val listItem = view?.findViewById(R.id.list_item) as TextView
@@ -52,11 +55,13 @@ class DataCursorAdapter(context: Context?, c: Cursor?) : CursorAdapter(context,
R.layout.list_layout, parent, false
)
}
+
// Set the data for the row
cursor.moveToPosition(position)
val listItemHeader = convertView?.findViewById(R.id.list_item_header) as TextView
val listItem = convertView?.findViewById(R.id.list_item) as TextView
val listDivider = convertView?.findViewById(R.id.list_divider) as View
+ val headerDivider = convertView?.findViewById(R.id.header_divider) as View
listItem.text = cursor.getString(cursor.getColumnIndex(ContactDatabase.ContactDatabase.FeedEntry.NAME_COLUMN))
if (position - 1 >= 0) {
@@ -67,19 +72,52 @@ class DataCursorAdapter(context: Context?, c: Cursor?) : CursorAdapter(context,
if (currentDate.equals(previousDate, ignoreCase = true)) {
// The dates are the same so abort everything as we already set the header before
listItemHeader.visibility = View.GONE
- listDivider.visibility = View.VISIBLE
+ if (isNightModeActive(convertView)) {
+ listDivider.visibility = View.GONE
+ listDivider.layoutParams.height = 3
+ } else { listDivider.visibility = View.VISIBLE }
} else {
// This is the first occurrence of this date so show the header
listItemHeader.visibility = View.VISIBLE
listItemHeader.text = currentDate
- listDivider.visibility = View.GONE
+ if (isNightModeActive(convertView)) {
+ listDivider.visibility = View.VISIBLE
+ headerDivider.visibility = View.VISIBLE
+ listDivider.layoutParams.height = 3
+ headerDivider.layoutParams.height = 3
+ } else { listDivider.visibility = View.GONE }
}
} else {
// This is position 0 and we need a header here
listItemHeader.visibility = View.VISIBLE
listItemHeader.text = formatter.format(Date(cursor.getLong(mDateColumnIndex)))
- listDivider.visibility = View.GONE
+ if (isNightModeActive(convertView)) {
+ listDivider.visibility = View.VISIBLE
+ listDivider.layoutParams.height = 3
+ headerDivider.visibility = View.VISIBLE
+ } else {
+ listDivider.visibility = View.GONE
+ headerDivider.visibility = View.GONE
+ }
}
return convertView
}
+
+ private fun isNightModeActive(context: View?): Boolean {
+ val defaultNightMode = AppCompatDelegate.getDefaultNightMode()
+ if (defaultNightMode == AppCompatDelegate.MODE_NIGHT_YES) {
+ return true
+ }
+ if (defaultNightMode == AppCompatDelegate.MODE_NIGHT_NO) {
+ return false
+ }
+ val currentNightMode = (context!!.resources.configuration.uiMode
+ and Configuration.UI_MODE_NIGHT_MASK)
+ when (currentNightMode) {
+ Configuration.UI_MODE_NIGHT_NO -> return false
+ Configuration.UI_MODE_NIGHT_YES -> return true
+ Configuration.UI_MODE_NIGHT_UNDEFINED -> return false
+ }
+ return false
+ }
}
\ No newline at end of file
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/EditContactActivity.kt b/android_app/app/src/main/java/com/apozas/contactdiary/EditContactActivity.kt
index 8222115..dec15ac 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/EditContactActivity.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/EditContactActivity.kt
@@ -21,7 +21,6 @@ import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.os.Bundle
-import android.text.format.DateFormat.is24HourFormat
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
@@ -29,8 +28,9 @@ import android.widget.EditText
import android.widget.RadioButton
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_editcontact.*
+import kotlinx.android.synthetic.main.activity_editcontact_inside.*
import java.text.DateFormat
+import java.text.SimpleDateFormat
import java.util.*
class EditContactActivity : AppCompatActivity() {
@@ -58,67 +58,116 @@ class EditContactActivity : AppCompatActivity() {
name_edit.setText(cursor.getString(cursor.getColumnIndex(feedEntry.NAME_COLUMN)))
place_edit.setText(cursor.getString(cursor.getColumnIndex(feedEntry.PLACE_COLUMN)))
- val timestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.DATETIME_COLUMN))
- val cal = Calendar.getInstance()
- cal.timeInMillis = timestamp
+ val timeFormat = SimpleDateFormat("H:mm")
+ val initCal = Calendar.getInstance()
+ initCal.timeInMillis = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_BEGIN_COLUMN))
- date_edit.setText(DateFormat.getDateInstance(DateFormat.MEDIUM).format(cal.time))
- time_edit.setText(DateFormat.getTimeInstance(DateFormat.SHORT).format(cal.time))
+ val endCal = Calendar.getInstance()
+ endCal.timeInMillis = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_END_COLUMN))
+
+ date_edit.setText(DateFormat.getDateInstance(DateFormat.MEDIUM).format(initCal.time))
+
+ if (!((initCal.get(Calendar.HOUR) == 0)
+ and (initCal.get(Calendar.MINUTE) == 0)
+ and (initCal.get(Calendar.SECOND) == 0)
+ and (initCal.get(Calendar.MILLISECOND) == 0))) {
+ inittime_edit.setText(timeFormat.format(initCal.time))
+ }
+
+ if (!((endCal.get(Calendar.HOUR) == 0)
+ and (endCal.get(Calendar.MINUTE) == 0)
+ and (endCal.get(Calendar.SECOND) == 0)
+ and (endCal.get(Calendar.MILLISECOND) == 0))) {
+ endtime_edit.setText(timeFormat.format(endCal.time))
+ }
if (cursor.getString(cursor.getColumnIndex(feedEntry.PHONE_COLUMN)) != ""){
phone_edit.setText(cursor.getString(cursor.getColumnIndex(feedEntry.PHONE_COLUMN)))
}
var relative = cursor.getInt(cursor.getColumnIndex(feedEntry.RELATIVE_COLUMN))
- if (relative%2==0) {relative = 2*relative+1} // Migration from 1.0.4 fix
+ if (relative%2==0) {relative = 2*relative+1}
+ else if (relative==-1) {relative = known_group.childCount-2} // Migration from 1.0.4 fix
val relativeBtn = known_group.getChildAt(relative) as RadioButton
relativeBtn.isChecked = true
var encounter = cursor.getInt(cursor.getColumnIndex(feedEntry.ENCOUNTER_COLUMN))
- if (encounter%2==0) {encounter = 2*encounter+1} // Migration from 1.0.4 fix
+ if (encounter%2==0) {encounter = 2*encounter+1}
+ else if (encounter==-1) {encounter = contact_indoor_outdoor.childCount-2} // Migration from 1.0.4 fix
val encounterBtn = contact_indoor_outdoor.getChildAt(encounter) as RadioButton
encounterBtn.isChecked = true
var closeContact = cursor.getInt(cursor.getColumnIndex(feedEntry.CLOSECONTACT_COLUMN))
- if (closeContact%2==0) {closeContact = 2*closeContact+1} // Migration from 1.0.4 fix
+ if (closeContact%2==0) {closeContact = 2*closeContact+1}
+ else if (closeContact==-1) {closeContact = distance_group.childCount-2} // Migration from 1.0.4 fix
val closeContactBtn = distance_group.getChildAt(closeContact) as RadioButton
closeContactBtn.isChecked = true
notes_edit.setText(cursor.getString(cursor.getColumnIndex(feedEntry.NOTES_COLUMN)))
+// Close the cursor after reading it
+ cursor.close()
+
// Listen to new values
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
- cal.set(Calendar.YEAR, year)
- cal.set(Calendar.MONTH, monthOfYear)
- cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ initCal.set(Calendar.YEAR, year)
+ initCal.set(Calendar.MONTH, monthOfYear)
+ initCal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
- date_edit.setText(DateFormat.getDateInstance().format(cal.time))
+ date_edit.setText(DateFormat.getDateInstance().format(initCal.time))
}
date_edit.setOnClickListener {
DatePickerDialog(
this@EditContactActivity, dateSetListener,
- cal.get(Calendar.YEAR),
- cal.get(Calendar.MONTH),
- cal.get(Calendar.DAY_OF_MONTH)
+ initCal.get(Calendar.YEAR),
+ initCal.get(Calendar.MONTH),
+ initCal.get(Calendar.DAY_OF_MONTH)
).show()
}
- val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
- cal.set(Calendar.HOUR_OF_DAY, hour)
- cal.set(Calendar.MINUTE, minute)
+ val initTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ initCal.set(Calendar.HOUR_OF_DAY, hour)
+ initCal.set(Calendar.MINUTE, minute)
+
+ inittime_edit.setText(timeFormat.format(initCal.time))
+ if (endtime_edit.text.isEmpty() or (endCal.timeInMillis < initCal.timeInMillis)) {
+ endCal.timeInMillis = initCal.timeInMillis
+ endCal.add(Calendar.MINUTE, 30)
+ endtime_edit.setText(timeFormat.format(endCal.time))
+ }
+ }
+
+ val is24Hour = android.text.format.DateFormat.is24HourFormat(applicationContext)
+
+ inittime_edit.setOnClickListener {
+ TimePickerDialog(
+ this@EditContactActivity, initTimeSetListener,
+ initCal.get(Calendar.HOUR_OF_DAY),
+ initCal.get(Calendar.MINUTE),
+ is24Hour
+ ).show()
+ }
- time_edit.setText(DateFormat.getTimeInstance(DateFormat.SHORT).format(cal.time))
+ val endTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ endCal.set(Calendar.HOUR_OF_DAY, hour)
+ endCal.set(Calendar.MINUTE, minute)
+ if (endCal.timeInMillis < initCal.timeInMillis) {
+ Toast.makeText(
+ this, R.string.incorrect_alarm_time, Toast.LENGTH_LONG
+ ).show()
+ } else {
+ endtime_edit.setText(timeFormat.format(endCal.time))
+ }
}
- val is24Hour = is24HourFormat(applicationContext)
- time_edit.setOnClickListener {
+ endtime_edit.setOnClickListener {
TimePickerDialog(
- this@EditContactActivity, timeSetListener,
- cal.get(Calendar.HOUR_OF_DAY),
- cal.get(Calendar.MINUTE),
+ this@EditContactActivity, endTimeSetListener,
+ endCal.get(Calendar.HOUR_OF_DAY),
+ endCal.get(Calendar.MINUTE),
is24Hour
).show()
}
@@ -146,26 +195,22 @@ class EditContactActivity : AppCompatActivity() {
contactCloseContactChoice = distance_group.indexOfChild(btn)
}
-// Compulsory text fields
+// Compulsory text field
var errorCount = 0
val contactName = name_edit.text.toString()
if (contactName.isEmpty()) {
name_edit.error = getString(R.string.compulsory_field)
errorCount++
}
- val contactPlace = place_edit.text.toString()
- if (contactPlace.isEmpty()) {
- place_edit.error = getString(R.string.compulsory_field)
- errorCount++
- }
-// Create new row
+// Create the updated row
if (errorCount == 0) {
val values = ContentValues().apply {
put(feedEntry.TYPE_COLUMN, "Contact")
put(feedEntry.NAME_COLUMN, contactName)
- put(feedEntry.PLACE_COLUMN, contactPlace)
- put(feedEntry.DATETIME_COLUMN, cal.timeInMillis)
+ put(feedEntry.PLACE_COLUMN, place_edit.text.toString())
+ put(feedEntry.TIME_BEGIN_COLUMN, initCal.timeInMillis)
+ put(feedEntry.TIME_END_COLUMN, endCal.timeInMillis)
put(feedEntry.PHONE_COLUMN, phone_edit.text.toString())
put(feedEntry.RELATIVE_COLUMN, relativeChoice)
put(feedEntry.CLOSECONTACT_COLUMN, contactCloseContactChoice)
@@ -211,16 +256,22 @@ class EditContactActivity : AppCompatActivity() {
)
cursor.moveToFirst()
- val timestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.DATETIME_COLUMN))
- val cal = Calendar.getInstance()
- cal.timeInMillis = timestamp
- cal.set(Calendar.DAY_OF_YEAR, Calendar.getInstance().get(Calendar.DAY_OF_YEAR))
+ val beginTimestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_BEGIN_COLUMN))
+ val initCal = Calendar.getInstance()
+ initCal.timeInMillis = beginTimestamp
+ initCal.set(Calendar.DAY_OF_YEAR, Calendar.getInstance().get(Calendar.DAY_OF_YEAR))
+
+ val endTimestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_END_COLUMN))
+ val endCal = Calendar.getInstance()
+ endCal.timeInMillis = endTimestamp
+ endCal.set(Calendar.DAY_OF_YEAR, initCal.get(Calendar.DAY_OF_YEAR))
val values = ContentValues().apply {
put(feedEntry.TYPE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.TYPE_COLUMN)))
put(feedEntry.NAME_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.NAME_COLUMN)))
put(feedEntry.PLACE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.PLACE_COLUMN)))
- put(feedEntry.DATETIME_COLUMN, cal.timeInMillis)
+ put(feedEntry.TIME_BEGIN_COLUMN, initCal.timeInMillis)
+ put(feedEntry.TIME_END_COLUMN, endCal.timeInMillis)
put(feedEntry.PHONE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.PHONE_COLUMN)))
put(feedEntry.RELATIVE_COLUMN, cursor.getInt(cursor.getColumnIndex(feedEntry.RELATIVE_COLUMN)))
put(feedEntry.COMPANIONS_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.COMPANIONS_COLUMN)))
@@ -237,6 +288,7 @@ class EditContactActivity : AppCompatActivity() {
applicationContext.resources.getString(R.string.entry_duplicated),
Toast.LENGTH_SHORT
).show()
+ cursor.close()
finish()
}
@@ -262,5 +314,4 @@ class EditContactActivity : AppCompatActivity() {
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.hideSoftInputFromWindow(currentFocus?.windowToken, 0)
}
-
}
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/EditEventActivity.kt b/android_app/app/src/main/java/com/apozas/contactdiary/EditEventActivity.kt
index 2ec11eb..566a0f4 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/EditEventActivity.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/EditEventActivity.kt
@@ -21,7 +21,6 @@ import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.os.Bundle
-import android.text.format.DateFormat.is24HourFormat
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
@@ -29,8 +28,9 @@ import android.widget.EditText
import android.widget.RadioButton
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_editevent.*
+import kotlinx.android.synthetic.main.activity_editevent_inside.*
import java.text.DateFormat
+import java.text.SimpleDateFormat
import java.util.*
class EditEventActivity : AppCompatActivity() {
@@ -47,7 +47,6 @@ class EditEventActivity : AppCompatActivity() {
// Get info from MainActivity
val info = intent.extras?.getString("entry")
-
val db = dbHelper.writableDatabase
val cursor: Cursor = db.rawQuery(
@@ -59,12 +58,29 @@ class EditEventActivity : AppCompatActivity() {
eventname_edit.setText(cursor.getString(cursor.getColumnIndex(feedEntry.NAME_COLUMN)))
eventplace_edit.setText(cursor.getString(cursor.getColumnIndex(feedEntry.PLACE_COLUMN)))
- val timestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.DATETIME_COLUMN))
- val cal = Calendar.getInstance()
- cal.timeInMillis = timestamp
+ val timeFormat = SimpleDateFormat("H:mm")
+ val initCal = Calendar.getInstance()
+ initCal.timeInMillis = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_BEGIN_COLUMN))
+
+ val endCal = Calendar.getInstance()
+ endCal.timeInMillis = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_END_COLUMN))
+
+ eventdate_edit.setText(DateFormat.getDateInstance(DateFormat.MEDIUM).format(initCal.time))
+
+ if (!((initCal.get(Calendar.HOUR) == 0)
+ and (initCal.get(Calendar.MINUTE) == 0)
+ and (initCal.get(Calendar.SECOND) == 0)
+ and (initCal.get(Calendar.MILLISECOND) == 0))) {
+ eventinittime_edit.setText(timeFormat.format(initCal.time))
+ }
+
+ if (!((endCal.get(Calendar.HOUR) == 0)
+ and (endCal.get(Calendar.MINUTE) == 0)
+ and (endCal.get(Calendar.SECOND) == 0)
+ and (endCal.get(Calendar.MILLISECOND) == 0))) {
+ eventendtime_edit.setText(timeFormat.format(endCal.time))
+ }
- eventdate_edit.setText(DateFormat.getDateInstance(DateFormat.MEDIUM).format(cal.time))
- eventtime_edit.setText(DateFormat.getTimeInstance(DateFormat.SHORT).format(cal.time))
if (cursor.getString(cursor.getColumnIndex(feedEntry.COMPANIONS_COLUMN)) != ""){
eventpeople_edit.setText(cursor.getString(cursor.getColumnIndex(feedEntry.COMPANIONS_COLUMN)))
}
@@ -73,50 +89,86 @@ class EditEventActivity : AppCompatActivity() {
}
var encounter = cursor.getInt(cursor.getColumnIndex(feedEntry.ENCOUNTER_COLUMN))
- if (encounter%2==0) {encounter = 2*encounter+1} // Migration from 1.0.4 fix
+ if (encounter%2==0) {encounter = 2*encounter+1}
+ else if (encounter==-1) {encounter = event_indoor_outdoor.childCount-2} // Migration from 1.0.4 fix
val encounterBtn = event_indoor_outdoor.getChildAt(encounter) as RadioButton
encounterBtn.isChecked = true
var closeContact = cursor.getInt(cursor.getColumnIndex(feedEntry.CLOSECONTACT_COLUMN))
- if (closeContact%2==0) {closeContact = 2*closeContact+1} // Migration from 1.0.4 fix
+ if (closeContact%2==0) {closeContact = 2*closeContact+1}
+ else if (closeContact==-1) {closeContact = eventclosecontact.childCount-2} // Migration from 1.0.4 fix
val closeContactBtn = eventclosecontact.getChildAt(closeContact) as RadioButton
closeContactBtn.isChecked = true
eventnotes_edit.setText(cursor.getString(cursor.getColumnIndex(feedEntry.NOTES_COLUMN)))
+// Close the cursor after reading it
+ cursor.close()
+
// Listen to new values
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
- cal.set(Calendar.YEAR, year)
- cal.set(Calendar.MONTH, monthOfYear)
- cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ initCal.set(Calendar.YEAR, year)
+ initCal.set(Calendar.MONTH, monthOfYear)
+ initCal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
- eventdate_edit.setText(DateFormat.getDateInstance().format(cal.time))
+ endCal.set(Calendar.YEAR, year)
+ endCal.set(Calendar.MONTH, monthOfYear)
+ endCal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+
+ eventdate_edit.setText(DateFormat.getDateInstance().format(initCal.time))
}
eventdate_edit.setOnClickListener {
DatePickerDialog(
this@EditEventActivity, dateSetListener,
- cal.get(Calendar.YEAR),
- cal.get(Calendar.MONTH),
- cal.get(Calendar.DAY_OF_MONTH)
+ initCal.get(Calendar.YEAR),
+ initCal.get(Calendar.MONTH),
+ initCal.get(Calendar.DAY_OF_MONTH)
).show()
}
- val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
- cal.set(Calendar.HOUR_OF_DAY, hour)
- cal.set(Calendar.MINUTE, minute)
+ val initTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ initCal.set(Calendar.HOUR_OF_DAY, hour)
+ initCal.set(Calendar.MINUTE, minute)
- eventtime_edit.setText(DateFormat.getTimeInstance(DateFormat.SHORT).format(cal.time))
+ eventinittime_edit.setText(timeFormat.format(initCal.time))
+ if (eventendtime_edit.text.isEmpty() or (endCal.timeInMillis < initCal.timeInMillis)) {
+ endCal.timeInMillis = initCal.timeInMillis
+ endCal.add(Calendar.MINUTE, 30)
+ eventendtime_edit.setText(timeFormat.format(endCal.time))
+ }
+ }
+
+ val is24Hour = android.text.format.DateFormat.is24HourFormat(applicationContext)
+ eventinittime_edit.setOnClickListener {
+ TimePickerDialog(
+ this@EditEventActivity, initTimeSetListener,
+ initCal.get(Calendar.HOUR_OF_DAY),
+ initCal.get(Calendar.MINUTE),
+ is24Hour
+ ).show()
}
- val is24Hour = is24HourFormat(applicationContext)
- eventtime_edit.setOnClickListener {
+ val endTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ endCal.set(Calendar.HOUR_OF_DAY, hour)
+ endCal.set(Calendar.MINUTE, minute)
+
+ if (endCal.timeInMillis < initCal.timeInMillis) {
+ Toast.makeText(
+ this, R.string.incorrect_alarm_time, Toast.LENGTH_LONG
+ ).show()
+ } else {
+ eventendtime_edit.setText(timeFormat.format(endCal.time))
+ }
+ }
+
+ eventendtime_edit.setOnClickListener {
TimePickerDialog(
- this@EditEventActivity, timeSetListener,
- cal.get(Calendar.HOUR_OF_DAY),
- cal.get(Calendar.MINUTE),
+ this@EditEventActivity, endTimeSetListener,
+ endCal.get(Calendar.HOUR_OF_DAY),
+ endCal.get(Calendar.MINUTE),
is24Hour
).show()
}
@@ -137,25 +189,22 @@ class EditEventActivity : AppCompatActivity() {
contactCloseContactChoice = eventclosecontact.indexOfChild(btn)
}
-// Compulsory text fields
+// Compulsory text field
var errorCount = 0
val eventName = eventname_edit.text.toString()
if (eventName.isEmpty()) {
eventname_edit.error = getString(R.string.compulsory_field)
errorCount++
}
- val eventPlace = eventplace_edit.text.toString()
- if (eventPlace.isEmpty()) {
- eventplace_edit.error = getString(R.string.compulsory_field)
- errorCount++
- }
-// Create new row
+
+// Create updated row
if (errorCount == 0) {
val values = ContentValues().apply {
put(feedEntry.TYPE_COLUMN, "Event")
put(feedEntry.NAME_COLUMN, eventName)
- put(feedEntry.PLACE_COLUMN, eventPlace)
- put(feedEntry.DATETIME_COLUMN, cal.timeInMillis)
+ put(feedEntry.PLACE_COLUMN, eventplace_edit.text.toString())
+ put(feedEntry.TIME_BEGIN_COLUMN, initCal.timeInMillis)
+ put(feedEntry.TIME_END_COLUMN, endCal.timeInMillis)
put(feedEntry.PHONE_COLUMN, eventphone_edit.text.toString())
put(feedEntry.COMPANIONS_COLUMN, eventpeople_edit.text.toString())
put(feedEntry.CLOSECONTACT_COLUMN, contactCloseContactChoice)
@@ -163,7 +212,7 @@ class EditEventActivity : AppCompatActivity() {
put(feedEntry.NOTES_COLUMN, eventnotes_edit.text.toString())
}
-// Update the database
+// Update the database
val selection = "_id LIKE ?"
val selectionArgs = arrayOf(info.toString())
db.update(feedEntry.TABLE_NAME, values, selection, selectionArgs)
@@ -203,16 +252,22 @@ class EditEventActivity : AppCompatActivity() {
)
cursor.moveToFirst()
- val timestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.DATETIME_COLUMN))
- val cal = Calendar.getInstance()
- cal.timeInMillis = timestamp
- cal.set(Calendar.DAY_OF_YEAR, Calendar.getInstance().get(Calendar.DAY_OF_YEAR))
+ val beginTimestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_BEGIN_COLUMN))
+ val initCal = Calendar.getInstance()
+ initCal.timeInMillis = beginTimestamp
+ initCal.set(Calendar.DAY_OF_YEAR, Calendar.getInstance().get(Calendar.DAY_OF_YEAR))
+
+ val endTimestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_END_COLUMN))
+ val endCal = Calendar.getInstance()
+ endCal.timeInMillis = endTimestamp
+ endCal.set(Calendar.DAY_OF_YEAR, initCal.get(Calendar.DAY_OF_YEAR))
val values = ContentValues().apply {
put(feedEntry.TYPE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.TYPE_COLUMN)))
put(feedEntry.NAME_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.NAME_COLUMN)))
put(feedEntry.PLACE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.PLACE_COLUMN)))
- put(feedEntry.DATETIME_COLUMN, cal.timeInMillis)
+ put(feedEntry.TIME_BEGIN_COLUMN, initCal.timeInMillis)
+ put(feedEntry.TIME_END_COLUMN, endCal.timeInMillis)
put(feedEntry.PHONE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.PHONE_COLUMN)))
put(feedEntry.RELATIVE_COLUMN, cursor.getInt(cursor.getColumnIndex(feedEntry.RELATIVE_COLUMN)))
put(feedEntry.COMPANIONS_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.COMPANIONS_COLUMN)))
@@ -229,7 +284,7 @@ class EditEventActivity : AppCompatActivity() {
applicationContext.resources.getString(R.string.entry_duplicated),
Toast.LENGTH_SHORT
).show()
-
+ cursor.close()
finish()
}
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/FeedReaderDbHelper.kt b/android_app/app/src/main/java/com/apozas/contactdiary/FeedReaderDbHelper.kt
index b6c9ea1..3ca7750 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/FeedReaderDbHelper.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/FeedReaderDbHelper.kt
@@ -26,13 +26,29 @@ class FeedReaderDbHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
if (oldVersion < 2) { db.execSQL(ContactDatabase.SQL_UPDATE_2) }
+ if (oldVersion < 3) {
+ db.execSQL(ContactDatabase.SQL_UPDATE_3)
+ MigrationTools().migrateTo3(db)
+ }
+ if (oldVersion < 4) {
+// Rename table to temporary name
+ db.execSQL(ContactDatabase.SQL_UPDATE_4_PART1)
+// Create new table
+ db.execSQL(ContactDatabase.SQL_CREATE_ENTRIES)
+// Move relevant information
+ db.execSQL(ContactDatabase.SQL_UPDATE_4_PART2)
+// Create new information (EndTime = BeginTime + Duration)
+ MigrationTools().migrateTo4(db)
+// Remove old table
+ db.execSQL(ContactDatabase.SQL_UPDATE_4_PART3)
+ }
}
override fun onDowngrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
- onUpgrade(db, oldVersion, newVersion)
+// onUpgrade(db, oldVersion, newVersion)
}
companion object {
// If you change the database schema, you must increment the database version.
- const val DATABASE_VERSION = 2
+ const val DATABASE_VERSION = 4
const val DATABASE_NAME = "ContactDiary.db"
}
@@ -41,11 +57,11 @@ class FeedReaderDbHelper(context: Context) : SQLiteOpenHelper(context, DATABASE_
val query = if (onlyRisky) {
"Select * from " + ContactDatabase.ContactDatabase.FeedEntry.TABLE_NAME +
- " WHERE " + ContactDatabase.ContactDatabase.FeedEntry.CLOSECONTACT_COLUMN + ">=1" +
- " ORDER BY " + ContactDatabase.ContactDatabase.FeedEntry.DATETIME_COLUMN + " DESC"
+ " WHERE " + ContactDatabase.ContactDatabase.FeedEntry.CLOSECONTACT_COLUMN + ">1" +
+ " ORDER BY " + ContactDatabase.ContactDatabase.FeedEntry.TIME_BEGIN_COLUMN + " DESC"
} else {
"Select * from " + ContactDatabase.ContactDatabase.FeedEntry.TABLE_NAME +
- " ORDER BY " + ContactDatabase.ContactDatabase.FeedEntry.DATETIME_COLUMN + " DESC"
+ " ORDER BY " + ContactDatabase.ContactDatabase.FeedEntry.TIME_BEGIN_COLUMN + " DESC"
}
return db.rawQuery(query, null)
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/MainActivity.kt b/android_app/app/src/main/java/com/apozas/contactdiary/MainActivity.kt
index 7c6ab1a..aadc2ac 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/MainActivity.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/MainActivity.kt
@@ -22,10 +22,14 @@ import android.os.Bundle
import android.view.*
import android.view.animation.Animation
import android.view.animation.AnimationUtils
-import android.widget.*
+import android.widget.AbsListView
+import android.widget.AdapterView
+import android.widget.ListView
+import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.PreferenceManager
-import kotlinx.android.synthetic.main.activity_main.*
+import kotlinx.android.synthetic.main.activity_main_inside.*
import java.util.*
@@ -37,17 +41,22 @@ class MainActivity : AppCompatActivity() {
private val dbHelper = FeedReaderDbHelper(this)
override fun onCreate(savedInstanceState: Bundle?) {
+ PreferenceManager.setDefaultValues(this, R.xml.preferences, false)
+ val preferences = PreferenceManager.getDefaultSharedPreferences(this)
+
super.onCreate(savedInstanceState)
+ when (preferences.getString("theme", "System")) {
+ "Dark" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
+ "Light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
+ "System" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
+ }
setContentView(R.layout.activity_main)
setSupportActionBar(findViewById(R.id.toolbar))
val notificationHandler = NotificationHandler()
notificationHandler.scheduleNotification(this)
- PreferenceManager.setDefaultValues(this, R.xml.preferences, false)
- val preferences = PreferenceManager.getDefaultSharedPreferences(this)
onlyRisky = preferences.getBoolean("closecontactonly", false)
-
restrict15LastDays()
viewData(onlyRisky)
@@ -124,14 +133,20 @@ class MainActivity : AppCompatActivity() {
return false
}
- override fun onActionItemClicked(actionMode: ActionMode, menuItem: MenuItem): Boolean {
+ override fun onActionItemClicked(
+ actionMode: ActionMode,
+ menuItem: MenuItem
+ ): Boolean {
when (menuItem.itemId) {
R.id.context_delete -> {
- for (item: Long in itemList) { deleteEntry(item) }
+ for (item: Long in itemList) {
+ deleteEntry(item)
+ }
Toast.makeText(
applicationContext,
- getString(if (itemList.size > 1) R.string.entries_deleted
- else R.string.entry_deleted
+ getString(
+ if (itemList.size > 1) R.string.entries_deleted
+ else R.string.entry_deleted
),
Toast.LENGTH_SHORT
).show()
@@ -141,11 +156,14 @@ class MainActivity : AppCompatActivity() {
return true
}
R.id.context_duplicate -> {
- for (item: Long in itemList) { duplicateEntry(item) }
+ for (item: Long in itemList) {
+ duplicateEntry(item)
+ }
Toast.makeText(
applicationContext,
- getString(if (itemList.size > 1) R.string.entries_duplicated
- else R.string.entry_duplicated
+ getString(
+ if (itemList.size > 1) R.string.entries_duplicated
+ else R.string.entry_duplicated
),
Toast.LENGTH_SHORT
).show()
@@ -173,10 +191,12 @@ class MainActivity : AppCompatActivity() {
) {
if (checked) {
itemList.add(position)
- actionMode.title = itemList.size.toString() + getString(R.string.entries_selected)
+ actionMode.title =
+ itemList.size.toString() + getString(R.string.entries_selected)
} else {
itemList.remove(position)
- actionMode.title = itemList.size.toString() + getString(R.string.entries_selected)
+ actionMode.title =
+ itemList.size.toString() + getString(R.string.entries_selected)
}
}
})
@@ -265,7 +285,6 @@ class MainActivity : AppCompatActivity() {
// Database operation
private fun viewData(onlyRisky: Boolean) {
val cursor = dbHelper.viewData(onlyRisky)
-
val adapter = DataCursorAdapter(this, cursor)
diarytable.adapter = adapter
@@ -282,7 +301,7 @@ class MainActivity : AppCompatActivity() {
// Define 'where' part of query.
val selection = "DELETE FROM ${ContactDatabase.ContactDatabase.FeedEntry.TABLE_NAME} " +
- "WHERE ${ContactDatabase.ContactDatabase.FeedEntry.DATETIME_COLUMN} <= " + fifteenDaysAgo.toString()
+ "WHERE ${ContactDatabase.ContactDatabase.FeedEntry.TIME_BEGIN_COLUMN} <= " + fifteenDaysAgo.toString()
// Issue SQL statement.
db.execSQL(selection)
}
@@ -300,22 +319,55 @@ class MainActivity : AppCompatActivity() {
)
cursor.moveToFirst()
- val timestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.DATETIME_COLUMN))
- val cal = Calendar.getInstance()
- cal.timeInMillis = timestamp
- cal.set(Calendar.DAY_OF_YEAR, Calendar.getInstance().get(Calendar.DAY_OF_YEAR))
+ val beginTimestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_BEGIN_COLUMN))
+ val initCal = Calendar.getInstance()
+ initCal.timeInMillis = beginTimestamp
+ initCal.set(Calendar.DAY_OF_YEAR, Calendar.getInstance().get(Calendar.DAY_OF_YEAR))
+
+ val endTimestamp = cursor.getLong(cursor.getColumnIndex(feedEntry.TIME_END_COLUMN))
+ val endCal = Calendar.getInstance()
+ endCal.timeInMillis = endTimestamp
+ endCal.set(Calendar.DAY_OF_YEAR, initCal.get(Calendar.DAY_OF_YEAR))
val values = ContentValues().apply {
- put(feedEntry.TYPE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.TYPE_COLUMN)))
- put(feedEntry.NAME_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.NAME_COLUMN)))
- put(feedEntry.PLACE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.PLACE_COLUMN)))
- put(feedEntry.DATETIME_COLUMN, cal.timeInMillis)
- put(feedEntry.PHONE_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.PHONE_COLUMN)))
- put(feedEntry.RELATIVE_COLUMN, cursor.getInt(cursor.getColumnIndex(feedEntry.RELATIVE_COLUMN)))
- put(feedEntry.COMPANIONS_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.COMPANIONS_COLUMN)))
- put(feedEntry.CLOSECONTACT_COLUMN, cursor.getInt(cursor.getColumnIndex(feedEntry.CLOSECONTACT_COLUMN)))
- put(feedEntry.ENCOUNTER_COLUMN, cursor.getInt(cursor.getColumnIndex(feedEntry.ENCOUNTER_COLUMN)))
- put(feedEntry.NOTES_COLUMN, cursor.getString(cursor.getColumnIndex(feedEntry.NOTES_COLUMN)))
+ put(
+ feedEntry.TYPE_COLUMN,
+ cursor.getString(cursor.getColumnIndex(feedEntry.TYPE_COLUMN))
+ )
+ put(
+ feedEntry.NAME_COLUMN,
+ cursor.getString(cursor.getColumnIndex(feedEntry.NAME_COLUMN))
+ )
+ put(
+ feedEntry.PLACE_COLUMN,
+ cursor.getString(cursor.getColumnIndex(feedEntry.PLACE_COLUMN))
+ )
+ put(feedEntry.TIME_BEGIN_COLUMN, initCal.timeInMillis)
+ put(feedEntry.TIME_END_COLUMN, endCal.timeInMillis)
+ put(
+ feedEntry.PHONE_COLUMN,
+ cursor.getString(cursor.getColumnIndex(feedEntry.PHONE_COLUMN))
+ )
+ put(
+ feedEntry.RELATIVE_COLUMN,
+ cursor.getInt(cursor.getColumnIndex(feedEntry.RELATIVE_COLUMN))
+ )
+ put(
+ feedEntry.COMPANIONS_COLUMN,
+ cursor.getString(cursor.getColumnIndex(feedEntry.COMPANIONS_COLUMN))
+ )
+ put(
+ feedEntry.CLOSECONTACT_COLUMN,
+ cursor.getInt(cursor.getColumnIndex(feedEntry.CLOSECONTACT_COLUMN))
+ )
+ put(
+ feedEntry.ENCOUNTER_COLUMN,
+ cursor.getInt(cursor.getColumnIndex(feedEntry.ENCOUNTER_COLUMN))
+ )
+ put(
+ feedEntry.NOTES_COLUMN,
+ cursor.getString(cursor.getColumnIndex(feedEntry.NOTES_COLUMN))
+ )
}
// Insert the new row
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/MigrationTools.kt b/android_app/app/src/main/java/com/apozas/contactdiary/MigrationTools.kt
new file mode 100644
index 0000000..78ad884
--- /dev/null
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/MigrationTools.kt
@@ -0,0 +1,77 @@
+package com.apozas.contactdiary
+
+/*
+ This file is part of Contact Diary.
+ Contact Diary is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ Contact Diary is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with Contact Diary. If not, see .
+ Copyright 2020 by Alex Pozas-Kerstjens (apozas)
+*/
+
+import android.content.ContentValues
+import android.database.sqlite.SQLiteDatabase
+import java.util.*
+
+class MigrationTools {
+ private val cal: Calendar = Calendar.getInstance()
+ private val feedEntry = ContactDatabase.ContactDatabase.FeedEntry
+
+ fun migrateTo3(dataBase: SQLiteDatabase) {
+ val query = "Select * from " + feedEntry.TABLE_NAME
+ val cursor = dataBase.rawQuery(query, null)
+
+ cursor.use { cursor ->
+ while (cursor.moveToNext()) {
+ val id = cursor.getInt(cursor.getColumnIndex("_id"))
+ val time = cursor.getLong(cursor.getColumnIndex(feedEntry.TIMESTAMP_COLUMN))
+ cal.timeInMillis = time
+ cal.set(Calendar.HOUR, 0)
+ cal.set(Calendar.MINUTE, 0)
+ cal.set(Calendar.SECOND, 0)
+ cal.set(Calendar.MILLISECOND, 0)
+
+ val values = ContentValues().apply {
+ put(feedEntry.TIMESTAMP_COLUMN, cal.timeInMillis)
+ put(feedEntry.DURATION_COLUMN, 60)
+ }
+// Update the database
+ val selection = "_id LIKE ?"
+ val selectionArgs = arrayOf(id.toString())
+ dataBase.update(feedEntry.TABLE_NAME, values, selection, selectionArgs)
+ }
+ }
+ }
+
+ fun migrateTo4(dataBase: SQLiteDatabase) {
+ val query = "Select * from tmp_table"
+ val cursor = dataBase.rawQuery(query, null)
+
+ cursor.use { cursor ->
+ while (cursor.moveToNext()) {
+ val id = cursor.getInt(cursor.getColumnIndex("_id"))
+ val time = cursor.getLong(cursor.getColumnIndex(feedEntry.TIMESTAMP_COLUMN))
+ val duration = cursor.getLong(cursor.getColumnIndex(feedEntry.DURATION_COLUMN))
+ val hours = duration / 60
+ val minutes = duration % 60
+ cal.timeInMillis = time
+ cal.add(Calendar.HOUR_OF_DAY, hours.toInt())
+ cal.add(Calendar.MINUTE, minutes.toInt())
+
+ val values = ContentValues().apply {
+ put(feedEntry.TIME_END_COLUMN, cal.timeInMillis)
+ }
+// Update the database
+ val selection = "_id LIKE ?"
+ val selectionArgs = arrayOf(id.toString())
+ dataBase.update(feedEntry.TABLE_NAME, values, selection, selectionArgs)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/NewContactActivity.kt b/android_app/app/src/main/java/com/apozas/contactdiary/NewContactActivity.kt
index f6608f7..e95104a 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/NewContactActivity.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/NewContactActivity.kt
@@ -27,8 +27,9 @@ import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_addcontact.*
+import kotlinx.android.synthetic.main.activity_addcontact_inside.*
import java.text.DateFormat
+import java.text.SimpleDateFormat
import java.util.*
class NewContactActivity : AppCompatActivity() {
@@ -42,40 +43,86 @@ class NewContactActivity : AppCompatActivity() {
setupUI(findViewById(R.id.newcontactlayout))
- val cal = Calendar.getInstance()
+ val initCal = Calendar.getInstance()
+ initCal.set(Calendar.HOUR_OF_DAY, 0)
+ initCal.set(Calendar.MINUTE, 0)
+ initCal.set(Calendar.SECOND, 0)
+ initCal.set(Calendar.MILLISECOND, 0)
+
+ val endCal = Calendar.getInstance()
+ endCal.set(Calendar.HOUR_OF_DAY, 0)
+ endCal.set(Calendar.MINUTE, 0)
+ endCal.set(Calendar.SECOND, 0)
+ endCal.set(Calendar.MILLISECOND, 0)
// Set current values
- date_input.setText(DateFormat.getDateInstance().format(cal.time))
+ date_input.setText(DateFormat.getDateInstance().format(initCal.time))
+
+ val timeFormat = SimpleDateFormat("H:mm")
// Listen to new values
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
- cal.set(Calendar.YEAR, year)
- cal.set(Calendar.MONTH, monthOfYear)
- cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ initCal.set(Calendar.YEAR, year)
+ initCal.set(Calendar.MONTH, monthOfYear)
+ initCal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
- date_input.setText(DateFormat.getDateInstance().format(cal.time))
+ endCal.set(Calendar.YEAR, year)
+ endCal.set(Calendar.MONTH, monthOfYear)
+ endCal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ date_input.setText(DateFormat.getDateInstance().format(initCal.time))
}
date_input.setOnClickListener {
- DatePickerDialog(this@NewContactActivity, dateSetListener,
- cal.get(Calendar.YEAR),
- cal.get(Calendar.MONTH),
- cal.get(Calendar.DAY_OF_MONTH)).show()
+ DatePickerDialog(
+ this@NewContactActivity, dateSetListener,
+ initCal.get(Calendar.YEAR),
+ initCal.get(Calendar.MONTH),
+ initCal.get(Calendar.DAY_OF_MONTH)
+ ).show()
}
- val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
- cal.set(Calendar.HOUR_OF_DAY, hour)
- cal.set(Calendar.MINUTE, minute)
+ val initTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ initCal.set(Calendar.HOUR_OF_DAY, hour)
+ initCal.set(Calendar.MINUTE, minute)
- time_input.setText(DateFormat.getTimeInstance(DateFormat.SHORT).format(cal.time))
+ inittime_input.setText(timeFormat.format(initCal.time))
+ if (endtime_input.text.isEmpty() or (endCal.timeInMillis < initCal.timeInMillis)) {
+ endCal.timeInMillis = initCal.timeInMillis
+ endCal.add(Calendar.MINUTE, 30)
+ endtime_input.setText(timeFormat.format(endCal.time))
+ }
}
val is24Hour = is24HourFormat(applicationContext)
- time_input.setOnClickListener {
- TimePickerDialog(this@NewContactActivity, timeSetListener,
- cal.get(Calendar.HOUR_OF_DAY),
- cal.get(Calendar.MINUTE),
+
+ inittime_input.setOnClickListener {
+ TimePickerDialog(
+ this@NewContactActivity, initTimeSetListener,
+ initCal.get(Calendar.HOUR_OF_DAY),
+ initCal.get(Calendar.MINUTE),
+ is24Hour
+ ).show()
+ }
+
+ val endTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ endCal.set(Calendar.HOUR_OF_DAY, hour)
+ endCal.set(Calendar.MINUTE, minute)
+
+ if (endCal.timeInMillis < initCal.timeInMillis) {
+ Toast.makeText(
+ this, R.string.incorrect_alarm_time, Toast.LENGTH_LONG
+ ).show()
+ } else {
+ endtime_input.setText(timeFormat.format(endCal.time))
+ }
+ }
+
+ endtime_input.setOnClickListener {
+ TimePickerDialog(
+ this@NewContactActivity, endTimeSetListener,
+ endCal.get(Calendar.HOUR_OF_DAY),
+ endCal.get(Calendar.MINUTE),
is24Hour
).show()
}
@@ -86,7 +133,6 @@ class NewContactActivity : AppCompatActivity() {
okButton_AddContact.setOnClickListener {
// Gets the data repository in write mode
val db = dbHelper.writableDatabase
-
var errorCount = 0
// Process RadioButtons
@@ -95,9 +141,6 @@ class NewContactActivity : AppCompatActivity() {
if (relativeId != -1) {
val btn: View = known_group.findViewById(relativeId)
relativeChoice = known_group.indexOfChild(btn)
- } else {
- known_question.error = getString(R.string.choose_option)
- errorCount++
}
val contactIndoorOutdoorId = contact_indoor_outdoor.checkedRadioButtonId
@@ -105,9 +148,6 @@ class NewContactActivity : AppCompatActivity() {
if (contactIndoorOutdoorId != -1) {
val btn: View = contact_indoor_outdoor.findViewById(contactIndoorOutdoorId)
contactIndoorOutdoorChoice = contact_indoor_outdoor.indexOfChild(btn)
- } else {
- encounter_question.error = getString(R.string.choose_option)
- errorCount++
}
val contactCloseContactId = distance_group.checkedRadioButtonId
@@ -115,38 +155,23 @@ class NewContactActivity : AppCompatActivity() {
if (contactCloseContactId != -1) {
val btn: View = distance_group.findViewById(contactCloseContactId)
contactCloseContactChoice = distance_group.indexOfChild(btn)
- } else {
- distance_question.error = getString(R.string.choose_option)
- errorCount++
}
-// Compulsory text fields
+// Compulsory text field
val contactName = name_input.text.toString()
if (contactName.isEmpty()) {
name_input.error = getString(R.string.compulsory_field)
errorCount++
}
- val contactPlace = place_input.text.toString()
- if (contactPlace.isEmpty()) {
- place_input.error = getString(R.string.compulsory_field)
- errorCount++
- }
-
-// Handle time field
- if (time_input.text.toString() == "") {
- cal.set(Calendar.HOUR_OF_DAY, 0)
- cal.set(Calendar.MINUTE, 0)
- cal.set(Calendar.SECOND, 0)
- cal.set(Calendar.MILLISECOND, 0)
- }
// Create a new map of values, where column names are the keys
if (errorCount == 0) {
val values = ContentValues().apply {
put(feedEntry.TYPE_COLUMN, "Contact")
put(feedEntry.NAME_COLUMN, contactName)
- put(feedEntry.PLACE_COLUMN, contactPlace)
- put(feedEntry.DATETIME_COLUMN, cal.timeInMillis)
+ put(feedEntry.PLACE_COLUMN, place_input.text.toString())
+ put(feedEntry.TIME_BEGIN_COLUMN, initCal.timeInMillis)
+ put(feedEntry.TIME_END_COLUMN, endCal.timeInMillis)
put(feedEntry.PHONE_COLUMN, phone_input.text.toString())
put(feedEntry.RELATIVE_COLUMN, relativeChoice)
put(feedEntry.CLOSECONTACT_COLUMN, contactCloseContactChoice)
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/NewEventActivity.kt b/android_app/app/src/main/java/com/apozas/contactdiary/NewEventActivity.kt
index d96bfdc..7bc49e1 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/NewEventActivity.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/NewEventActivity.kt
@@ -20,15 +20,15 @@ import android.app.TimePickerDialog
import android.content.ContentValues
import android.content.Context
import android.os.Bundle
-import android.text.format.DateFormat.is24HourFormat
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
-import kotlinx.android.synthetic.main.activity_addevent.*
+import kotlinx.android.synthetic.main.activity_addevent_inside.*
import java.text.DateFormat
+import java.text.SimpleDateFormat
import java.util.*
class NewEventActivity : AppCompatActivity() {
@@ -41,44 +41,87 @@ class NewEventActivity : AppCompatActivity() {
setSupportActionBar(findViewById(R.id.toolbar))
setupUI(findViewById(R.id.neweventlayout))
- val cal = Calendar.getInstance()
+ val initCal = Calendar.getInstance()
+ initCal.set(Calendar.HOUR_OF_DAY, 0)
+ initCal.set(Calendar.MINUTE, 0)
+ initCal.set(Calendar.SECOND, 0)
+ initCal.set(Calendar.MILLISECOND, 0)
+
+ val endCal = Calendar.getInstance()
+ endCal.set(Calendar.HOUR_OF_DAY, 0)
+ endCal.set(Calendar.MINUTE, 0)
+ endCal.set(Calendar.SECOND, 0)
+ endCal.set(Calendar.MILLISECOND, 0)
// Set current values
- eventdate_input.setText(DateFormat.getDateInstance().format(cal.time))
+ eventdate_input.setText(DateFormat.getDateInstance().format(initCal.time))
+
+ val timeFormat = SimpleDateFormat("H:mm")
// Listen to new values
val eventdateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
- cal.set(Calendar.YEAR, year)
- cal.set(Calendar.MONTH, monthOfYear)
- cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ initCal.set(Calendar.YEAR, year)
+ initCal.set(Calendar.MONTH, monthOfYear)
+ initCal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
- eventdate_input.setText(DateFormat.getDateInstance().format(cal.time))
+ endCal.set(Calendar.YEAR, year)
+ endCal.set(Calendar.MONTH, monthOfYear)
+ endCal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+
+ eventdate_input.setText(DateFormat.getDateInstance().format(initCal.time))
}
eventdate_input.setOnClickListener {
DatePickerDialog(
this@NewEventActivity, eventdateSetListener,
- cal.get(Calendar.YEAR),
- cal.get(Calendar.MONTH),
- cal.get(Calendar.DAY_OF_MONTH)
+ initCal.get(Calendar.YEAR),
+ initCal.get(Calendar.MONTH),
+ initCal.get(Calendar.DAY_OF_MONTH)
).show()
}
- val eventtimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
- cal.set(Calendar.HOUR_OF_DAY, hour)
- cal.set(Calendar.MINUTE, minute)
+ val initTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ initCal.set(Calendar.HOUR_OF_DAY, hour)
+ initCal.set(Calendar.MINUTE, minute)
- eventtime_input.setText(DateFormat.getTimeInstance(DateFormat.SHORT).format(cal.time))
+ eventinittime_input.setText(timeFormat.format(initCal.time))
+ if (eventendtime_input.text.isEmpty() or (endCal.timeInMillis < initCal.timeInMillis)) {
+ endCal.timeInMillis = initCal.timeInMillis
+ endCal.add(Calendar.MINUTE, 30)
+ eventendtime_input.setText(timeFormat.format(endCal.time))
+ }
+ }
+
+ val is24Hour = android.text.format.DateFormat.is24HourFormat(applicationContext)
+ eventinittime_input.setOnClickListener {
+ TimePickerDialog(
+ this@NewEventActivity, initTimeSetListener,
+ initCal.get(Calendar.HOUR_OF_DAY),
+ initCal.get(Calendar.MINUTE),
+ is24Hour
+ ).show()
}
- val is24Hour = is24HourFormat(applicationContext)
- eventtime_input.setOnClickListener {
+ val endTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
+ endCal.set(Calendar.HOUR_OF_DAY, hour)
+ endCal.set(Calendar.MINUTE, minute)
+
+ if (endCal.timeInMillis < initCal.timeInMillis) {
+ Toast.makeText(
+ this, R.string.incorrect_alarm_time, Toast.LENGTH_LONG
+ ).show()
+ } else {
+ eventendtime_input.setText(timeFormat.format(endCal.time))
+ }
+ }
+
+ eventendtime_input.setOnClickListener {
TimePickerDialog(
- this@NewEventActivity, eventtimeSetListener,
- cal.get(Calendar.HOUR_OF_DAY),
- cal.get(Calendar.MINUTE),
+ this@NewEventActivity, endTimeSetListener,
+ endCal.get(Calendar.HOUR_OF_DAY),
+ endCal.get(Calendar.MINUTE),
is24Hour
).show()
}
@@ -89,7 +132,6 @@ class NewEventActivity : AppCompatActivity() {
okButton_AddEvent.setOnClickListener {
// Gets the data repository in write mode
val db = dbHelper.writableDatabase
-
var errorCount = 0
// Process RadioButtons
@@ -98,9 +140,6 @@ class NewEventActivity : AppCompatActivity() {
if (eventIndoorOutdoorId != -1) {
val btn: View = event_indoor_outdoor.findViewById(eventIndoorOutdoorId)
eventIndoorOutdoorChoice = event_indoor_outdoor.indexOfChild(btn)
- } else {
- event_encounter_question.error = getString(R.string.choose_option)
- errorCount++
}
val eventCloseContactId = eventclosecontact.checkedRadioButtonId
@@ -108,38 +147,23 @@ class NewEventActivity : AppCompatActivity() {
if (eventCloseContactId != -1) {
val btn: View = eventclosecontact.findViewById(eventCloseContactId)
eventCloseContactChoice = eventclosecontact.indexOfChild(btn)
- } else {
- closecontact_question.error = getString(R.string.choose_option)
- errorCount++
}
-// Compulsory text fields
+// Compulsory text field
val eventName = eventname_input.text.toString()
if (eventName.isEmpty()) {
eventname_input.error = getString(R.string.compulsory_field)
errorCount++
}
- val eventPlace = eventplace_input.text.toString()
- if (eventPlace.isEmpty()) {
- eventplace_input.error = getString(R.string.compulsory_field)
- errorCount++
- }
-
-// Handle time field
- if (eventtime_input.text.toString() == "") {
- cal.set(Calendar.HOUR_OF_DAY, 0)
- cal.set(Calendar.MINUTE, 0)
- cal.set(Calendar.SECOND, 0)
- cal.set(Calendar.MILLISECOND, 0)
- }
// Create a new map of values, where column names are the keys
if (errorCount == 0) {
val values = ContentValues().apply {
put(feedEntry.TYPE_COLUMN, "Event")
put(feedEntry.NAME_COLUMN, eventName)
- put(feedEntry.PLACE_COLUMN, eventPlace)
- put(feedEntry.DATETIME_COLUMN, cal.timeInMillis)
+ put(feedEntry.PLACE_COLUMN, eventplace_input.text.toString())
+ put(feedEntry.TIME_BEGIN_COLUMN, initCal.timeInMillis)
+ put(feedEntry.TIME_END_COLUMN, endCal.timeInMillis)
put(feedEntry.PHONE_COLUMN, eventphone_input.text.toString())
put(feedEntry.COMPANIONS_COLUMN, eventpeople_input.text.toString())
put(feedEntry.ENCOUNTER_COLUMN, eventIndoorOutdoorChoice)
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/SettingsActivity.kt b/android_app/app/src/main/java/com/apozas/contactdiary/SettingsActivity.kt
index b8bfd23..b176c27 100644
--- a/android_app/app/src/main/java/com/apozas/contactdiary/SettingsActivity.kt
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/SettingsActivity.kt
@@ -15,12 +15,24 @@ package com.apozas.contactdiary
Copyright 2020 by Alex Pozas-Kerstjens (apozas)
*/
-import android.content.ComponentName
+import android.app.Activity
+import android.content.*
import android.content.pm.PackageManager
+import android.database.Cursor
+import android.database.Cursor.*
+import android.database.sqlite.SQLiteDatabase
+import android.net.Uri
import android.os.Bundle
+import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
+import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.*
+import com.apozas.contactdiary.ContactDatabase.Companion.SQL_CREATE_ENTRIES
+import com.apozas.contactdiary.ContactDatabase.Companion.SQL_DELETE_ENTRIES
+import java.io.BufferedReader
+import java.io.InputStreamReader
+import java.text.SimpleDateFormat
class SettingsActivity : AppCompatActivity() {
@@ -32,6 +44,10 @@ class SettingsActivity : AppCompatActivity() {
}
class SettingsFragment : PreferenceFragmentCompat() {
+ private val EXPORT_DB = 1
+ private val IMPORT_DB = 2
+ private val feedEntry = ContactDatabase.ContactDatabase.FeedEntry
+
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
@@ -40,7 +56,8 @@ class SettingsActivity : AppCompatActivity() {
val oldTime = preferences.getString("reminder_time", "21:00").toString()
val reminderTime = findPreference("reminder_time")
- val reminderToggle = findPreference("reminder_toggle") as SwitchPreference
+ val reminderToggle =
+ findPreference("reminder_toggle") as SwitchPreference
reminderTime?.setOnPreferenceChangeListener { _, newValue ->
var isTimeGood = true
@@ -66,22 +83,60 @@ class SettingsActivity : AppCompatActivity() {
if ((newValue.toString() != oldTime) && isTimeGood) {
prefsedit.putString("reminder_time", newValue)
prefsedit.apply()
- Toast.makeText(context, getString(R.string.alarm_modified), Toast.LENGTH_SHORT).show()
+ Toast.makeText(context, getString(R.string.alarm_modified), Toast.LENGTH_SHORT)
+ .show()
updateNotificationPreferences(reminderToggle.isEnabled)
true
} else {
prefsedit.putString("reminder_time", oldTime)
prefsedit.apply()
- false }
+ false
+ }
}
reminderToggle.setOnPreferenceChangeListener { _, newValue ->
updateNotificationPreferences(newValue as Boolean)
true
}
+
+ val prefTheme = findPreference("theme")
+ prefTheme!!.setOnPreferenceChangeListener { _, newValue ->
+ when (newValue) {
+ "Light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
+ "Dark" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
+ "System" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
+ }
+ true
+ }
+
+ val export = findPreference("export")
+ export!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
+ createFile()
+ true
+ }
+
+ val import = findPreference("import")
+ import!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
+ readFile()
+ true
+ }
}
- private fun updateNotificationPreferences(on: Boolean) {
+ override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
+ if ((requestCode == EXPORT_DB) && (resultCode == Activity.RESULT_OK)) {
+ // The result data contains a URI for the document or directory that
+ // the user selected.
+ resultData?.data?.also { uri ->
+ exportDB(requireActivity().applicationContext, uri)
+ }
+ }
+ if ((requestCode == IMPORT_DB) && (resultCode == Activity.RESULT_OK)) {
+ resultData?.data?.also { uri ->
+ importDB(requireActivity().applicationContext, uri)
+ }
+ }
+ }
+ private fun updateNotificationPreferences(on: Boolean) {
val receiver = ComponentName(
requireActivity().applicationContext, NotificationReceiver::class.java
)
@@ -101,5 +156,191 @@ class SettingsActivity : AppCompatActivity() {
)
}
}
+
+ private fun exportDB(context: Context, uri: Uri) {
+ val dbHelper = FeedReaderDbHelper(context)
+ val dateFormatter = SimpleDateFormat("yyyy-LL-dd-HH:mm")
+ try {
+ val csvWriter = context.contentResolver.openOutputStream(uri)
+ val db: SQLiteDatabase = dbHelper.readableDatabase
+ val cursor: Cursor = db.rawQuery(
+ "SELECT * FROM ${feedEntry.TABLE_NAME}",
+ null
+ )
+ val columnNames =
+ cursor.columnNames.drop(1).toMutableList() // We don't care of the _id column
+ columnNames[columnNames.indexOf("CloseContact")] = "DistanceKept"
+ csvWriter!!.write(
+ columnNames.joinToString(separator = "\t", postfix = "\n").toByteArray()
+ )
+ while (cursor.moveToNext()) {
+ //Which column you want to export
+ val columns = cursor.columnCount
+ val arrStr = mutableListOf()
+ for (i in 1 until columns) { // We don't care of the _id column
+ when (columnNames[i - 1]) {
+ "BeginTime" -> arrStr.add(dateFormatter.format(cursor.getLong(i)))
+ "EndTime" -> arrStr.add(dateFormatter.format(cursor.getLong(i)))
+ "Relative" -> arrStr.add(
+ when (cursor.getInt(i)) {
+ -1 -> ""
+ 0 -> ""
+ 1 -> "Yes"
+ 3 -> "No"
+ else -> cursor.getInt(i).toString()
+ }
+ )
+ "EncounterType" -> arrStr.add(
+ when (cursor.getInt(i)) {
+ -1 -> ""
+ 1 -> "Indoors"
+ 3 -> "Outdoors"
+ else -> cursor.getInt(i).toString()
+ }
+ )
+ "DistanceKept" -> arrStr.add(
+ when (cursor.getInt(i)) {
+ -1 -> ""
+ 1 -> "Yes"
+ 3 -> "No"
+ 5 -> "Unsure"
+ else -> cursor.getInt(i).toString()
+ }
+ )
+ else -> when (cursor.getType(i)) {
+ FIELD_TYPE_STRING -> arrStr.add(cursor.getString(i))
+ FIELD_TYPE_INTEGER -> arrStr.add(cursor.getLong(i).toString())
+ FIELD_TYPE_NULL -> arrStr.add("")
+ }
+ }
+ }
+ csvWriter!!.write(
+ arrStr.joinToString(separator = "\t", postfix = "\n").toByteArray()
+ )
+ }
+ csvWriter.close()
+ cursor.close()
+ Toast.makeText(context, getString(R.string.export_success), Toast.LENGTH_LONG).show()
+ } catch (sqlEx: Exception) {
+ Log.e("Export", sqlEx.message, sqlEx)
+ }
+ }
+
+ private fun importDB(context: Context, uri: Uri) {
+ val dbHelper = FeedReaderDbHelper(context)
+ val db = dbHelper.writableDatabase
+ val csvReader = BufferedReader(
+ InputStreamReader(
+ context.contentResolver.openInputStream(
+ uri
+ )
+ )
+ )
+
+ val columnNames = csvReader.readLine().split("\t")
+ if (columnNames != listOf(
+ feedEntry.TYPE_COLUMN, feedEntry.NAME_COLUMN, feedEntry.PLACE_COLUMN,
+ feedEntry.TIME_BEGIN_COLUMN, feedEntry.TIME_END_COLUMN, feedEntry.PHONE_COLUMN,
+ feedEntry.RELATIVE_COLUMN, feedEntry.COMPANIONS_COLUMN,
+ feedEntry.ENCOUNTER_COLUMN, "DistanceKept", feedEntry.NOTES_COLUMN
+ )
+ ) {
+ Toast.makeText(
+ requireActivity().applicationContext,
+ getString(R.string.import_fail),
+ Toast.LENGTH_LONG
+ ).show()
+ } else {
+ val dateFormatter = SimpleDateFormat("yyyy-MM-dd-HH:mm")
+ try {
+ db.execSQL(SQL_DELETE_ENTRIES)
+ db.execSQL(SQL_CREATE_ENTRIES)
+ var nextLine = csvReader.readLine()
+ while (nextLine != null) {
+ var nextLineList = nextLine.split("\t")
+ val type = nextLineList[0]
+ val name = nextLineList[1]
+ val place = nextLineList[2]
+ val beginTime = nextLineList[3]
+ val endTime = nextLineList[4]
+ val phone = nextLineList[5]
+ val relative = nextLineList[6]
+ val companions = nextLineList[7]
+ val encounterType = nextLineList[8]
+ val distance = nextLineList[9]
+ val notes = nextLineList[10]
+
+ val values = ContentValues().apply {
+ put(feedEntry.TYPE_COLUMN, type)
+ put(feedEntry.NAME_COLUMN, name)
+ put(feedEntry.PLACE_COLUMN, place)
+ put(feedEntry.TIME_BEGIN_COLUMN, dateFormatter.parse(beginTime).time)
+ put(feedEntry.TIME_END_COLUMN, dateFormatter.parse(endTime).time)
+ put(feedEntry.PHONE_COLUMN, phone)
+ put(
+ feedEntry.RELATIVE_COLUMN, when (relative) {
+ "Yes" -> 1
+ "No" -> 3
+ else -> -1
+ }
+ )
+ put(
+ feedEntry.CLOSECONTACT_COLUMN, when (distance) {
+ "Yes" -> 1
+ "No" -> 3
+ "Unsure" -> 5
+ else -> -1
+ }
+ )
+ put(
+ feedEntry.ENCOUNTER_COLUMN, when (encounterType) {
+ "Indoors" -> 1
+ "Outdoors" -> 3
+ else -> -1
+ }
+ )
+ put(feedEntry.COMPANIONS_COLUMN, companions)
+ put(feedEntry.NOTES_COLUMN, notes)
+ }
+ db?.insert(feedEntry.TABLE_NAME, null, values)
+ nextLine = csvReader.readLine()
+ }
+ Toast.makeText(context, getString(R.string.import_success), Toast.LENGTH_LONG).show()
+ } catch (e: java.lang.Exception) {
+ e.printStackTrace()
+ Toast.makeText(context, getString(R.string.import_notfound), Toast.LENGTH_LONG)
+ .show()
+ }
+ }
+ }
+
+ private fun createFile() {
+ val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "text/csv"
+ putExtra(Intent.EXTRA_TITLE, "ContactDiary.csv")
+ }
+ startActivityForResult(intent, EXPORT_DB)
+ }
+
+ private fun readFile() {
+ val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "text/csv"
+ }
+ try {
+ startActivityForResult(
+ Intent.createChooser(intent, getString(R.string.import_select)),
+ IMPORT_DB
+ )
+ } catch (ex: ActivityNotFoundException) {
+ // Potentially direct the user to the Market with a Dialog
+ Toast.makeText(
+ requireActivity().applicationContext,
+ "Please install a File Manager",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
}
}
diff --git a/android_app/app/src/main/java/com/apozas/contactdiary/ThanksActivity.kt b/android_app/app/src/main/java/com/apozas/contactdiary/ThanksActivity.kt
new file mode 100644
index 0000000..b430d76
--- /dev/null
+++ b/android_app/app/src/main/java/com/apozas/contactdiary/ThanksActivity.kt
@@ -0,0 +1,58 @@
+package com.apozas.contactdiary
+
+/*
+ This file is part of Contact Diary.
+ Contact Diary is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+ Contact Diary is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with Contact Diary. If not, see .
+ Copyright 2020 by Alex Pozas-Kerstjens (apozas)
+*/
+
+import android.os.Bundle
+import android.text.method.LinkMovementMethod
+import android.widget.TextView
+import androidx.appcompat.app.AppCompatActivity
+
+class ThanksActivity : AppCompatActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_thanks)
+
+ val homeScreen = findViewById(R.id.thanks_homescreen)
+ homeScreen.movementMethod = LinkMovementMethod.getInstance()
+
+ val dutch = findViewById(R.id.thanks_dutch)
+ dutch.movementMethod = LinkMovementMethod.getInstance()
+
+ val finnish = findViewById(R.id.thanks_finnish)
+ finnish.movementMethod = LinkMovementMethod.getInstance()
+
+ val french = findViewById(R.id.thanks_french)
+ french.movementMethod = LinkMovementMethod.getInstance()
+
+ val german = findViewById(R.id.thanks_german)
+ german.movementMethod = LinkMovementMethod.getInstance()
+
+ val indonesian = findViewById(R.id.thanks_indonesian)
+ indonesian.movementMethod = LinkMovementMethod.getInstance()
+
+ val italian = findViewById(R.id.thanks_italian)
+ italian.movementMethod = LinkMovementMethod.getInstance()
+
+ val polish = findViewById(R.id.thanks_polish)
+ polish.movementMethod = LinkMovementMethod.getInstance()
+
+ val portuguese = findViewById(R.id.thanks_portuguese)
+ portuguese.movementMethod = LinkMovementMethod.getInstance()
+
+ val swedish = findViewById(R.id.thanks_swedish)
+ swedish.movementMethod = LinkMovementMethod.getInstance()
+ }
+}
\ No newline at end of file
diff --git a/android_app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/android_app/app/src/main/res/drawable/ic_launcher_foreground.xml
similarity index 75%
rename from android_app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
rename to android_app/app/src/main/res/drawable/ic_launcher_foreground.xml
index 3a9779d..44f0cb7 100644
--- a/android_app/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ b/android_app/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -1,12 +1,11 @@
+ android:viewportWidth="47"
+ android:viewportHeight="47">
+ android:translateY="12"
+ android:translateX="12">
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_addcontact_inside.xml b/android_app/app/src/main/res/layout/activity_addcontact_inside.xml
new file mode 100644
index 0000000..5fc5970
--- /dev/null
+++ b/android_app/app/src/main/res/layout/activity_addcontact_inside.xml
@@ -0,0 +1,335 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_addevent.xml b/android_app/app/src/main/res/layout/activity_addevent.xml
index 2b1eddb..8506703 100644
--- a/android_app/app/src/main/res/layout/activity_addevent.xml
+++ b/android_app/app/src/main/res/layout/activity_addevent.xml
@@ -1,275 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_addevent_inside.xml b/android_app/app/src/main/res/layout/activity_addevent_inside.xml
new file mode 100644
index 0000000..b46f930
--- /dev/null
+++ b/android_app/app/src/main/res/layout/activity_addevent_inside.xml
@@ -0,0 +1,297 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_editcontact.xml b/android_app/app/src/main/res/layout/activity_editcontact.xml
index b2118f3..d9fe5ff 100644
--- a/android_app/app/src/main/res/layout/activity_editcontact.xml
+++ b/android_app/app/src/main/res/layout/activity_editcontact.xml
@@ -1,329 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_editcontact_inside.xml b/android_app/app/src/main/res/layout/activity_editcontact_inside.xml
new file mode 100644
index 0000000..11c360d
--- /dev/null
+++ b/android_app/app/src/main/res/layout/activity_editcontact_inside.xml
@@ -0,0 +1,350 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_editevent.xml b/android_app/app/src/main/res/layout/activity_editevent.xml
index 7704124..7703a41 100644
--- a/android_app/app/src/main/res/layout/activity_editevent.xml
+++ b/android_app/app/src/main/res/layout/activity_editevent.xml
@@ -1,300 +1,11 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_editevent_inside.xml b/android_app/app/src/main/res/layout/activity_editevent_inside.xml
new file mode 100644
index 0000000..338b069
--- /dev/null
+++ b/android_app/app/src/main/res/layout/activity_editevent_inside.xml
@@ -0,0 +1,322 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_main.xml b/android_app/app/src/main/res/layout/activity_main.xml
index d255398..e41687d 100644
--- a/android_app/app/src/main/res/layout/activity_main.xml
+++ b/android_app/app/src/main/res/layout/activity_main.xml
@@ -7,142 +7,6 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_main_inside.xml b/android_app/app/src/main/res/layout/activity_main_inside.xml
new file mode 100644
index 0000000..f98eeca
--- /dev/null
+++ b/android_app/app/src/main/res/layout/activity_main_inside.xml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/activity_privacy.xml b/android_app/app/src/main/res/layout/activity_privacy.xml
index ac60eeb..613170f 100644
--- a/android_app/app/src/main/res/layout/activity_privacy.xml
+++ b/android_app/app/src/main/res/layout/activity_privacy.xml
@@ -1,7 +1,6 @@
diff --git a/android_app/app/src/main/res/layout/activity_thanks.xml b/android_app/app/src/main/res/layout/activity_thanks.xml
new file mode 100644
index 0000000..471d06a
--- /dev/null
+++ b/android_app/app/src/main/res/layout/activity_thanks.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/layout/list_layout.xml b/android_app/app/src/main/res/layout/list_layout.xml
index 46caff0..4c4a0f3 100644
--- a/android_app/app/src/main/res/layout/list_layout.xml
+++ b/android_app/app/src/main/res/layout/list_layout.xml
@@ -4,15 +4,16 @@
android:layout_height="match_parent"
android:orientation="vertical" >
-
+
+ android:background="@color/colorDivider"
+ android:layout_marginLeft="@dimen/margin_divider"
+ android:layout_marginRight="@dimen/margin_divider"
+ android:contextClickable="false"
+ android:visibility="gone"/>
+
+
+
Data
Hora
Lloc
- Acompanyants (opcional)
+ Acompanyants
Creus que vas mantenir la distància?
Nom
Familiar o amic proper?
Creus que vau mantenir la distància?
- Telèfon (opcional)
+ Telèfon
No estic segur
Tipus de trobada
A l\'interior
@@ -25,7 +25,6 @@
Esdeveniment guardat
Editar esdeveniment
Editar contacte
- Hora (opcional)
Opcions
Entrada eliminada
Digues-me què en penses de l\'app, o problemes que has trobat
@@ -48,7 +47,7 @@
" entrades seleccionades"
Política de privacitat
Diari de Contactes es distribueix amb l\'esperança que sigui útil, però SENSE CAP GARANTIA; ni tan sols amb la garantia implícita de COMERCIALITZACIÓ o d\'IDONEITAT PER A UN PROPÒSIT PARTICULAR. Aquesta pàgina s’utilitza per informar els visitants sobre les meves polítiques sobre la recopilació, l’ús i la divulgació d’Informació Personal si algú decideix utilitzar Diari de Contactes. En resum, i com que Diari de Contactes no pot connectar-se a l\'internet, cap Informació Personal mai s’emmagatzemarà ni copiarà fora del dispositiu de l’usuari. Si decideixes utilitzar Diari de Contactes, acceptes la recopilació (cap) i l’ús d\'informació en relació amb aquesta política. La Informació Personal que Diari de Contactes recull s’utilitza per proporcionar el seu servei. Com s\'ha explicitat anteriorment, jo no puc i per tant no faré servir ni compartiré la teva informació amb ningú.
- L\'ús de Diari de Contactes requereix que introdueixis certa informació identificativa, com Noms, Llocs i (opcionalment) números de Teléfon. La informació que Diari de Contactes sol·licita es mantindrá al teu dispositiu i no la recopilaré de cap manera.
+ L\'ús de Diari de Contactes requereix que introdueixis certa informació identificativa, com noms i (opcionalment) llocs i números de telèfon. La informació que Diari de Contactes sol·licita es mantindrá al teu dispositiu i no la recopilaré de cap manera.
Les Cookies són fitxers amb una petita quantitat de dades que s’utilitzen habitualment com a identificadors únics anònims. Les Cookies s’envien al navegador des dels llocs web que visites i s’emmagatzemen a la memòria interna del dispositiu.\n\nDiari de Contactes no utilitza cap Cookies, ni pròpies ni de tercers.\n\nIgualment, cap servei és delegat a tercers. La informació que introdueixes a Diari de Contactes no surt mai del teu dispositiu.
Una vegada més, cap informació que introdueixes a Diari de Contactes no surt mai del teu dispositiu. Aquest fet es pot avaluar sempre inspeccionant el codi font de Diari de Contactes, que està disponible a www.github.com/apozas/contactdiary. Per tant, la seva seguretat i integritat està relacionada amb la seguretat física i la integritat del teu dispositiu, de la qual no assumeixo cap responsabilitat.
És possible que actualitzi aquesta Política de Privacitat de tant en tant. Per tant, et recomano que revisis aquesta pàgina periòdicament per si hi ha canvis. Jo notificaré qualsevol canvi publicant la nova Política de Privacitat en aquesta pàgina.\n\nAquesta política és efectiva a partir del 08-09-2020
@@ -67,5 +66,32 @@
Entrades duplicades
Fes-ne una còpia avui
Seleccionar
- Notes (opcional)
+ Notes
+ Gràcies
+ Sobre
+ Encara que Diari de Contactes va començar com un projecte en solitari, es va beneficiar d\'inestimables aportacions altruistes de moltes persones. El meu sincer agraïment a tothom en aquesta pàgina.
+ Dreceres de pantalla d\'inici - GenosseFlosse
+ Traducció a l\'holandès - Tonyinspace i Vistaus
+ Traducció al finlandès - Mikko95
+ Traducció al francès- matthus
+ Traducció a l\'alemany - GenosseFlosse, FloEdelmann, jensMF, leso-kn and mkamp
+ Traducció a l\'italià - igor-cali and lrt84
+ Traducció a l\'indonesi - hexatester
+ Traducció al polonès - wasikr7
+ Traducció al portuguès - riuri (Brasil)
+ Traducció al suec - nlssn
+ Tema
+ Clar
+ Fosc
+ Seguir sistema
+ Còpia de seguretat i restauració
+ Importar base de dades
+ Carregar una base de dades desada
+ Exportar base de dades
+ Desar la base de dades en format CSV
+ Base de dades desada
+ Ha hagut un problema amb la base de dades
+ Base de dades carregada
+ No s\'ha trobat l\'arxiu
+ Selecciona la base de dades a importar
diff --git a/android_app/app/src/main/res/values-de/strings.xml b/android_app/app/src/main/res/values-de/strings.xml
index 518c7ab..7f023e8 100644
--- a/android_app/app/src/main/res/values-de/strings.xml
+++ b/android_app/app/src/main/res/values-de/strings.xml
@@ -10,12 +10,12 @@
Datum
Uhrzeit
Ort
- Begleitpersonen (optional)
+ Begleitpersonen
Glaubst du, du hast genug Abstand eingehalten?
Name
Verwandte*r oder enge*r Freund*in?
Glaubst du, ihr habt genug Abstand eingehalten?
- Telefonnummer (optional)
+ Telefonnummer
Nicht sicher
Art der Begegnung
Drinnen
@@ -25,7 +25,6 @@
Gruppenbegegnung gespeichert
Gruppenbegegnung bearbeiten
Begegnung bearbeiten
- Uhrzeit (optional)
Optionen
Eintrag gelöscht
Erzähl mir, was du von der App hältst oder melde Probleme, die dir auffallen
@@ -48,7 +47,7 @@
" einträge ausgewählt"
Datenschutzrichtlinien
Kontakttagebuch wird in der Hoffnung entwickelt, dass es nützlich ist, jedoch OHNE JEGLICHE GARANTIE; ebenso ohne jegliche Gewährleistung von MÄNGELFREIHEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK. Diese Seite wird verwendet, um Besucher über meine Richtlinien bezüglich der Sammlung, Verwendung und Veröffentlichung von persönlichen Daten im Zusammenhang, mit der Nutzung von Kontakttagebuch zu informieren. Kurz gesagt: da sich Kontakttagebuch nicht mit dem Internet verbinden kann, werden keine persönlichen Informationen außerhalb des Gerätes des Benutzers gespeichert. Wenn du dich für die Nutzung von Kontakttagebuch entscheidest, stimmst du der Sammlung (keine) und der Nutzung von Informationen im Rahmen dieser Richtlinie zu. Die persönlichen Informationen, die Kontakttagebuch sammelt, werden für die Bereitstellung der Dienstleistungen der App verwendet. Wie bereits ausdrücklich dargelegt, kann und werde ich keine deiner Daten an Dritte weitergeben.
- Die Verwendung von Kontakttagebuch erfordert die Eingabe bestimmter persönlich identifizierenden Daten, wie Namen, Orte und (optional) Telefonnummern. Die Informationen, die Kontakttagebuch anfordert, werden auf deinem Gerät gespeichert und werden von mir in keiner Weise gesammelt.
+ Die Verwendung von Kontakttagebuch erfordert die Eingabe bestimmter persönlich identifizierenden Daten, wie namen und (optional) orte und telefonnummern. Die Informationen, die Kontakttagebuch anfordert, werden auf deinem Gerät gespeichert und werden von mir in keiner Weise gesammelt.
Cookies sind Dateien mit wenig Inhalt, die häufig als anonyme, eindeutige Identifikatoren verwendet werden. Diese werden von den Webseiten, die du besuchst, an deinen Browser gesendet und auf dem internen Speicher deines Geräts gespeichert.\n\nKontakttagebuch verwendet keine Cookies, weder eigene noch von Drittanbietern.\n\nAußerdem wird auch keine Dienstleistung an Drittanbieter ausgelagert. Die Informationen, die du in Kontakttagebuch eingibst, verlassen niemals dein Gerät.
Nochmals, keine Information, die du in Kontakttagebuch eingibst, verlässt jemals dein Gerät. Diese Tatsache kann immer überprüft werden, indem der Quellcode der App inspiziert wird, der hier zu finden ist: www.github.com/apozas/contactdiary. So ist die Sicherheit und Integrität der App von der physischen Sicherheit und Integrität deines Geräts abhängig, für die ich keine Verantwortung übernehme.
Ich kann diese Datenschutzerklärung von Zeit zu Zeit aktualisieren, daher wird empfohlen, diese Seite regelmäßig auf Änderungen zu überprüfen. Ich werde dich über alle Änderungen informieren, indem ich die neue Datenschutzrichtlinie auf dieser Seite veröffentliche.\n\nDiese Richtlinie gilt ab 2020-09-08
@@ -67,5 +66,27 @@
Einträge verdoppelt
Eintrag für heute kopieren
Auswählen
- Notizen (optional)
+ Notizen
+ Danksagungen
+ Über
+ Während Kontakttagebuch als Einzelprojekt begann, profitierte es von wertvollen, altruistischen Beiträgen vieler Menschen. Mein aufrichtiger Dank an alle auf dieser Seite genannten.
+ Schnellzugriffe für den Startbildschirm - GenosseFlosse
+ Niederländische Übersetzung - Tonyinspace und Vistaus
+ Finnische Übersetzung - Mikko95
+ Französische Übersetzung - matthus
+ Deutsche Übersetzung - GenosseFlosse, FloEdelmann, jensMF, leso-kn und mkamp
+ Italienische Übersetzung - igor-cali und lrt84
+ Indonesische Übersetzung - hexatester
+ Polnische Übersetzung - wasikr7
+ Portugiesische Übersetzung - riuri (Brasilien)
+ Schwedische Übersetzung - nlssn
+ Design
+ Hell
+ Dunkel
+ Dem System-Design folgen
+ Sichern und Wiederherstellen
+ Datenbank importieren
+ Gespeicherte Datenbank laden
+ Datenbank exportieren
+ Speichere die Datenbank im CSV-Format
diff --git a/android_app/app/src/main/res/values-es/strings.xml b/android_app/app/src/main/res/values-es/strings.xml
index 8a506a4..1753514 100644
--- a/android_app/app/src/main/res/values-es/strings.xml
+++ b/android_app/app/src/main/res/values-es/strings.xml
@@ -9,12 +9,12 @@
Fecha
Hora
Lugar
- Acompañantes (opcional)
+ Acompañantes
¿Crees que mantuviste la distancia?
Nombre
¿Es familiar o amigo cercano?
¿Crees que respetásteis la distancia?
- Teléfono (opcional)
+ Teléfono
No sé
Tipo de encuentro
Lugar cerrado
@@ -22,7 +22,6 @@
El diario está vacío
Contacto guardado
Evento guardado
- Hora (opcional)
Editar evento
Editar contacto
Entrada eliminada
@@ -47,7 +46,7 @@
" entradas seleccionadas"
Política de privacidad
Diario de Contactos es distribuido con la esperanza de que sea útil, pero SIN NINGUNA GARANTÍA; ni siquiera con las garantías implícitas de COMERCIABILIDAD o APTITUD PARA UN PROPÓSITO PARTICULAR.\n\nEsta página está diseñada para informar a los visitantes acerca de mis políticas en cuanto a la colección, uso y revelación de Información Personal en caso de que alguien decidiera utilizar Diario de Contactos.\n\nEn resumen, dado que Diario de Contactos no puede conectarse con internet, ninguna Información Personal será almacenada o copiada fuera del dispositivo del usuario.\n\nSi decides utilizar Diario de Contactos, aceptas la colección (ninguna) y uso de información en los términos recogidos en esta política. La Información Personal que Diario de Contactos colecciona es utilizada únicamente para proporcionar su servicio. Tal y como se explicita anteriormente, no puedo y consecuentemente jamás utilizaré ni compartiré tu información con nadie.
- El uso de Diario de Contactos requiere que introduzcas cierta información de identificación personal, a saber: nombres, lugares y (opcionalmente) números de teléfono. La información que Diario de Contactos solicita permanece en todo momento en tu dispositivo y no es coleccionada en ningún modo por mi parte.
+ El uso de Diario de Contactos requiere que introduzcas cierta información de identificación personal, a saber: nombres y (opcionalmente) lugares y números de teléfono. La información que Diario de Contactos solicita permanece en todo momento en tu dispositivo y no es coleccionada en ningún modo por mi parte.
Las cookies son archivos con una pequeña cantidad de datos que comúnmente se utilizan como identificadores únicos anónimos. Estas cookies son enviadas a tu navegador desde las páginas que visitas y se almacenan en la memoria interna de tu dispositivo.\n\nDiario de Contactos no utiliza ningún tipo de cookies, ni propias ni de terceras personas.\n\nDe la misma manera, ningún servicio es delegado a terceras personas. La información que introduces en Diario de Contactos nunca abandona tu dispositivo.
Una vez más, ningún tipo de información que introduzcas a Diario de Contactos jamás abandona tu dispositivo. Esta afirmación siempre puede comprobarse mediante la inspección del código fuente de Diario de Contactos, el cual está disponible en www.github.com/apozas/contactdiary. Consecuentemente, su seguridad e integridad está conectada a la seguridad e integridad física de tu dispositivo, de las cuales no asumo ninguna responsabilidad.
Puedo actualizar esta Política de Privacidad de vez en cuando. Consecuentemente, es aconsejable revisar esta página periódicamente en busca de cambios. Te notificaré de cualquier cambio a través de la publicación de la nueva Política de Privacidad en esta página.\n\nEsta política toma efecto desde 2020-09-08
@@ -66,5 +65,32 @@
Entradas duplicadas
Hacer copia hoy
Seleccionar
- Notas (opcional)
+ Notas
+ Gracias
+ Acerca de
+ Aunque Diario de Contactos comenzó como un proyecto en solitario, se ha beneficiado de las invaluables contribuciones altruistas de muchas personas. Mi más sincero agradecimiento a todos en esta página.
+ Accesos directos - GenosseFlosse
+ Traducción al holandés - Tonyinspace y Vistaus
+ Traducción al finlandés - Mikko95
+ Traducción al francés - matthus
+ Traducción al alemán - GenosseFlosse, FloEdelmann, jensMF, leso-kn y mkamp
+ Traducción al italiano - igor-cali y lrt84
+ Traducción al indonesio - hexatester
+ Traducción al polaco - wasikr7
+ Traducción al portugués - riuri (Brasil)
+ Traducción al sueco - nlssn
+ Tema
+ Claro
+ Oscuro
+ Seguir sistema
+ Guardar la base de datos en formato CSV
+ Exportar base de datos
+ Cargar una base de datos guardada
+ Importar base de datos
+ Copia de seguridad y restauración
+ Base de datos guardada
+ Hay un problema con la base de datos
+ Base de datos cargada
+ No se ha encontrado el archivo
+ Selecciona la base de datos a importar
\ No newline at end of file
diff --git a/android_app/app/src/main/res/values-fi/strings.xml b/android_app/app/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..9e06e2d
--- /dev/null
+++ b/android_app/app/src/main/res/values-fi/strings.xml
@@ -0,0 +1,83 @@
+
+
+ Yhteystietopäiväkirja
+ Asetukset
+ Uusi yhteystieto
+ Uusi tapahtuma
+ Tapahtuman nimi
+ Ei
+ Kyllä
+ Päivämäärä
+ Aika
+ Paikka
+ Seuralaiset
+ Luuletko, että pidit etäisyyden?
+ Nimi
+ Sukulainen vai läheinen ystävä?
+ Luuletko, että pidit etäisyyden?
+ Puhelinnumero
+ Epävarma
+ Kohtaamisen tyyppi
+ Sisätiloissa
+ Ulkona
+ Päiväkirja on tyhjä
+ Yhteystieto tallennettu
+ Tapahtuma tallennettu
+ Muokkaa tapahtumaa
+ Muokkaa yhteystietoa
+ Vaihtoehdot
+ Merkintä poistettu
+ Kerro minulle mitä mieltä olet sovelluksesta tai ongelmista, joita olet kohdannut
+ Ota yhteyttä kehittäjään
+ Tarjoa minulle kahvit
+ Kenen kanssa olet ollut tänään?
+ Lisää yhteystietosi päiväkirjaan
+ Valitse vaihtoehto
+ Pakollinen kenttä
+ Muokkaa
+ Poista
+ Hälytystä muokattu
+ Aseta oikea aika
+ Päivittäinen muistutus
+ Valitse aika
+ Näytä vain läheiset yhteystiedot
+ Lisää
+ Asetukset
+ Merkinnät poistettu
+ " merkinnät valittu"
+ Tietosuojakäytäntö
+ Yhteystietopäiväkirja jaetaan siinä toivossa, että se olisi hyödyllinen, mutta ILMAN MITÄÄN TAKUUTA; ilman edes epäsuoraa takuuta KAUPALLISUUDESTA tai SOVELTUVUUDESTA TIETTYYN TARKOITUKSEEN. Tätä sivua käytetään tiedottamaan kävijöille minun käytännöistäni henkilökohtaisten tietojen keruun, käytön, ja paljastumisen suhteen, jos joku päättää käyttää Yhteystietopäiväkirjaa. Lyhyesti sanottuna, ja koska Yhteystietopäiväkirja ei voi muodostaa yhteyttä Internetiin, mitään henkilötietoja ei tallenneta eikä kopioida käyttäjän laitteen ulkopuolelle. Jos päätät käyttää Yhteystietopäiväkirjaa, niin suostut tietojen keruuseen (ei mitään) ja käyttöön tähän käytäntöön liittyen. Henkilökohtaisia tietoja, joita Yhteystietopäiväkirja kerää, käytetään sen palvelun tarjoamiseen. Kuten edellä on todettu, en voi ja enkä näin ollen käytä tai jaa tietojasi kenenkään kanssa.
+ Yhteystietopäiväkirjan käyttö edellyttää, että syötät tiettyjä henkilökohtaisesti tunnistettavissa olevia tietoja, eli nimiä ja (vapaaehtoisesti) paikkoja ja puhelinnumeroita. Tiedot, joita Yhteystieto Päiväkirja pyytää, säilytetään laitteellasi ja minä en kerää niitä millään tavalla.
+ Evästeet ovat tiedostoja, joissa on pieni määrä tietoja, joita käytetään yleisesti nimettöminä yksilöllisinä tunnisteina. Nämä lähetetään selaimeesi sivustoilta, joilla käyt ja jotka tallennetaan laitteesi sisäiseen muistiin.\n\nYhteystiedot Päiväkirja ei käytä mitään evästeitä, ei ensimmäisen osapuolen eikä kolmannen osapuolen.\n\nSamalla tavalla mitään palvelua ei ole delegoitu kolmansille osapuolille. Yhteystiedot Päiväkirjalle antamasi tiedot eivät koskaan poistu laitteestasi.
+ Edelleen, mitään Yhteystietopäiväkirjaan syöttämiäsi tietoja ei koskaan lähde laitteeltasi. Tämä seikka voidaan aina arvioida tarkastamalla Yhteystietopäiväkirjan lähdekoodia, joka on saatavilla osoitteessa www.github.com/apozas/contactdiary. Näin ollen sovelluksen turvallisuus ja eheys liittyvät laitteesi fyysiseen turvallisuuteen ja eheyteen, joista en ota vastuuta.
+ Saatan päivittää tätä tietosuojakäytäntöä ajoittain. Täten sinua kehotetaan tarkastelemaan tätä sivua säännöllisin väliajoin muutosten varalta. Ilmoitan sinulle kaikista muutoksista julkaisemalla uuden tietosuojakäytännön tälle sivulle.\n\nTämä politiikka on voimassa 2020-09-08 alkaen
+ Jos sinulla on kysyttävää tai ehdotuksia tästä tietosuojakäytännöstä, älä epäröi ottaa yhteyttä minuun contactdiary@alexpozas.com (mieluiten englanniksi).
+ Muutokset tähän tietosuojakäytäntöön
+ Tietojen keruu ja käyttö
+ Evästeet ja palveluntarjoajat
+ Turvallisuus
+ Ota yhteyttä minuun
+ Paina (+) aloittaaksesi yhteystietojen lisäämisen
+ Sovellusversio
+
+ Arvostele sovellus
+ Jos pidät sovelluksesta, arvostele se, jotta se voi tavoittaa enemmän ihmisiä, jotka saattavat pitää sitä hyödyllisenä
+ Merkintä kopioitu
+ Merkinnät kopioitu
+ Tee kopio tänään
+ Valitse
+ Kiitos
+ Tietoja
+ Huomautukset
+ Vaikka Yhteystietopäiväkirja aloitti yksityisprojektina, se on hyötynyt monien ihmisten korvaamattomasta ja pyyteettömästä panoksesta. Rehelliset kiitokseni kaikille tällä sivulla oleville.
+ Kotinäytön pikakuvakkeet - GenosseFlosse
+ Hollanninkielinen käännös - Tonyinspace ja Vistaus
+ Suomenkielinen käännös - Mikko95
+ Ranskankielinen käännös - matthus
+ Saksankielinen käännös - GenosseFlosse, FloEdelmann, jensMF, leso-kn ja mkamp
+ Italiankielinen käännös - igor-cali ja lrt84
+ Indonesiankielinen käännös - hexatester
+ Puolankielinen käännös - wasikr7
+ Portugalkielinen käännös - riuri (Brasilia)
+ Ruotsinkielinen käännös - nlssn
+
diff --git a/android_app/app/src/main/res/values-fr/strings.xml b/android_app/app/src/main/res/values-fr/strings.xml
index 8eb06cf..54cd0c8 100644
--- a/android_app/app/src/main/res/values-fr/strings.xml
+++ b/android_app/app/src/main/res/values-fr/strings.xml
@@ -4,18 +4,18 @@
Paramètres
Nouveau contact
Nouvel événement
- Nom de l\'évènement
+ Nom de l\'événement
Non
Oui
Date
Heure
Lieu
- Personnes présentes (optionnel)
+ Personnes présentes
Pensez-vous avoir maintenu la distance?
Nom
Famille ou ami proche?
Pensez-vous avoir respecté la distance entre vous?
- Téléphone (optionnel)
+ Téléphone
Pas sûr
Type de rencontre
À l\'intérieur
@@ -25,7 +25,6 @@
Événement enregistré
Modifier l\'événement
Modifier le contact
- Heure (optionnel)
Options
Entrée supprimée
Dîtes-moi ce que vous pensez de l\'application, ou les problèmes que vous avez rencontrés
@@ -47,9 +46,8 @@
Entrées supprimées
" entrées sélectionnées"
Charte de confidentialité
- Journal des Contacts est distribué dans l\'espoir qu\'il sera utile, MAIS SANS AUCUNE GARANTIE; sans même la garantie implicite de COMMERCIALITÉ ou d\'ADAPTATION À UN USAGE PARTICULIER. Ce message a pour but d\'informer les visiteurs à propos de mes politiques de collecte, d\'utilisation et de partage d\'informations personnelles des personnes ayant décidées d\'utiliser Journal des Contacts.
-Pour faire court, sachant que Journal des Contacts ne peut pas se connecter à Internet, aucune information personnelle ne sera stockée ou copiée en dehors de l\'appareil de l\'utilisateur. Si vous choisissez d\'utiliser Journal des Contacts, alors vous devez accepter la collecte (aucune) et l\'utilisation d\'informations au regard de cette politique. Les informations personnelles que Journal des Contacts collecte sont utilisées afin de fournir son service. Comme explicité ci-dessus, je ne peux pas et n\'utiliserais ou ne partagerais pas vos informations à quiconque.
- L\'utilisation de Journal des Contacts exige que vous saisissiez certaines informations personnelles identifiables, à savoir les Noms, Lieux et (optionnellement) les Numéros de téléphone. Les informations que Journal des Contacts demande seront conservées sur votre appareil et ne seront en aucun cas collectées par moi.
+ Journal des Contacts est distribué dans l\'espoir qu\'il sera utile, MAIS SANS AUCUNE GARANTIE; sans même la garantie implicite de COMMERCIALITÉ ou d\'ADAPTATION À UN USAGE PARTICULIER. Ce message a pour but d\'informer les visiteurs à propos de mes politiques de collecte, d\'utilisation et de partage d\'informations personnelles des personnes ayant décidées d\'utiliser Journal des Contacts. Pour faire court, sachant que Journal des Contacts ne peut pas se connecter à Internet, aucune information personnelle ne sera stockée ou copiée en dehors de l\'appareil de l\'utilisateur. Si vous choisissez d\'utiliser Journal des Contacts, alors vous devez accepter la collecte (aucune) et l\'utilisation d\'informations au regard de cette politique. Les informations personnelles que Journal des Contacts collecte sont utilisées afin de fournir son service. Comme explicité ci-dessus, je ne peux pas et n\'utiliserais ou ne partagerais pas vos informations à quiconque.
+ L\'utilisation de Journal des Contacts exige que vous saisissiez certaines informations personnelles identifiables, à savoir les noms et (optionnellement) lieux et les numéros de téléphone. Les informations que Journal des Contacts demande seront conservées sur votre appareil et ne seront en aucun cas collectées par moi.
Les cookies sont des fichiers contenant une petite quantité de données qui sont couramment utilisés comme identificateurs uniques anonymes. Ceux-ci sont envoyés à votre navigateur à partir des sites Web que vous visitez et sont stockés dans la mémoire interne de votre appareil.\n\nJournal des Contacts n\'utilise aucun cookie, ni propriétaires ni de tiers\n\nDe la même manière, aucun service n\'est délégué à des tiers. Les informations que vous entrez dans Journal des Contacts ne quittent jamais votre appareil.
Encore une fois, aucune des informations que vous entrez dans Journal des Contacts ne quitte votre appareil. Vous pouvez toujours le vérifier en inspectant le code source de Journal des Contacts, disponible sur www.github.com/apozas/contactdiary. Dès lors, leur sécurité et leur intégrité sont liées à la sécurité physique et à l\'intégrité de votre appareil, dont je ne suis en aucun cas responsable.
Il se peut que je mette à jour cette Charte de Confidentialité de temps à autre. Ainsi, je vous conseille de consulter cette page régulièrement pour surveiller toute modification. Je vous informerai de tout changement en affichant la nouvelle Charte de Confidentialité sur cette page.\n\nCette charte est en vigueur à partir du 08/09/2020
@@ -68,5 +66,7 @@ Pour faire court, sachant que Journal des Contacts ne peut pas se connecter à I
Entrées dupliquées
Faire une copie aujourd\'hui
Sélectionner
- Notes (optionnel)
+ Notes
+ Merci
+ À propos
diff --git a/android_app/app/src/main/res/values-id/strings.xml b/android_app/app/src/main/res/values-id/strings.xml
new file mode 100644
index 0000000..ddb9dde
--- /dev/null
+++ b/android_app/app/src/main/res/values-id/strings.xml
@@ -0,0 +1,83 @@
+
+
+ Catatan Kontak
+ Pengaturan
+ Kontak baru
+ Acara baru
+ Nama acara
+ Tidak
+ Ya
+ Tanggal
+ Waktu
+ Lokasi
+ Pendamping
+ Apakah Anda pikir Anda menjaga jarak?
+ Nama
+ Kerabat atau teman dekat?
+ Apakah Kalian menjaga jarak?
+ Telepon
+ Tidak yakin
+ Jenis pertemuan
+ Dalam ruangan
+ Luar ruangan
+ Catatan kosong
+ Kontak disimpan
+ Acara disimpan
+ Edit acara
+ Edit kontak
+ Pilihan
+ Entri dihapus
+ Beri tahu saya pendapat Anda tentang aplikasi, atau masalah yang Anda temui
+ Hubungi pengembang
+ Belikan aku kopi
+ Dengan siapa Anda hari ini?
+ Tambahkan kontak Anda ke buku harian
+ Harap pilih satu opsi
+ Wajib diisi
+ Edit
+ Hapus
+ Alarm diubah
+ Harap masukkan waktu yang benar
+ Pengingat harian
+ Pilih waktu
+ Tampilkan hanya kontak dekat saja
+ Lainnya
+ Pengaturan
+ Entri dihapus
+ " entri terpilih"
+ Kebijakan privasi
+ Catatan Kontak didistribusikan dengan harapan bermanfaat, tetapi TANPA JAMINAN APA PUN; bahkan tanpa jaminan tersirat tentang DIPERDAGANGKAN atau KESESUAIAN UNTUK TUJUAN TERTENTU. Halaman ini digunakan untuk memberi tahu pengunjung mengenai kebijakan saya dengan pengumpulan, penggunaan, dan pengungkapan Informasi Pribadi jika ada yang memutuskan untuk menggunakan Catatan Kontak. Singkatnya, dan karena Catatan Kontak tidak dapat terhubung ke internet, tidak ada Informasi Pribadi yang akan disimpan atau disalin di luar perangkat pengguna. Jika Anda memilih untuk menggunakan Catatan Kontak, Anda menyetujui pengumpulan (tidak ada) dan penggunaan informasi terkait dengan kebijakan ini. Informasi Pribadi yang dikumpulkan Catatan Kontak digunakan untuk menyediakan layanannya. Seperti yang dijelaskan di atas, saya tidak dapat dan karenanya tidak akan menggunakan atau membagikan informasi Anda dengan siapa pun.
+ Penggunaan Catatan Kontak mengharuskan Anda memasukkan informasi pengenal pribadi tertentu, yaitu nama dan (opsional) tempat dan nomor telepon. Informasi yang diminta Catatan Kontak akan disimpan di perangkat Anda dan tidak dikumpulkan oleh saya dengan cara apa pun.
+ Kuki adalah file dengan sejumlah kecil data yang biasanya digunakan sebagai pengenal unik anonim. Ini dikirim ke browser Anda dari situs web yang Anda kunjungi dan disimpan di memori internal perangkat Anda.\n\nCatatan Kontak tidak menggunakan kuki apa pun, baik pihak pertama maupun pihak ketiga.\n\nDengan cara yang sama, tidak layanan didelegasikan kepada pihak ketiga. Informasi yang Anda masukkan ke Catatan Kontak tidak pernah meninggalkan perangkat Anda.
+ Sekali lagi, tidak ada informasi yang Anda masukkan ke Catatan Kontak yang pernah keluar dari perangkat Anda. Fakta ini selalu dapat dievaluasi dengan memeriksa kode sumber Catatan Kontak, yang tersedia di www.github.com/apozas/contactdiary. Karenanya, keamanan dan integritasnya terkait dengan keamanan fisik dan integritas perangkat Anda, yang saya tidak bertanggung jawab.
+ Saya dapat memperbarui Kebijakan Privasi ini dari waktu ke waktu. Dengan demikian, Anda disarankan untuk meninjau halaman ini secara berkala untuk setiap perubahan. Saya akan memberi tahu Anda tentang perubahan apa pun dengan memposting Kebijakan Privasi baru di halaman ini.\n\nKebijakan ini berlaku mulai 08-09-2020
+ Jika Anda memiliki pertanyaan atau saran tentang Kebijakan Privasi ini, jangan ragu untuk menghubungi saya di contactdiary@alexpozas.com (sebaiknya dalam bahasa Inggris).
+ Perubahan pada kebijakan privasi ini
+ Pengumpulan dan penggunaan informasi
+ Kuki dan penyedia layanan
+ Keamanan
+ Hubungi saya
+ Tekan (+) untuk mulai menambahkan kontak
+ Versi aplikasi
+
+ Beri nilai aplikasi
+ Jika Anda menyukai aplikasinya, beri peringkat dan ulas agar dapat menjangkau lebih banyak orang yang mungkin merasakan kegunaannya
+ Entri digandakan
+ Entri digandakan
+ Buat salinan hari ini
+ Pilih
+ Catatan
+ Terima kasih
+ Tentang
+ Meskipun Catatan Kontak dimulai sebagai proyek solo, ia memperoleh manfaat dari kontribusi altruistik yang tak ternilai dari banyak orang. Terima kasih yang tulus kepada semua orang di halaman ini.
+ Pintasan layar beranda - GenosseFlosse
+ Terjemahan bahasa Belanda - Tonyinspace dan Vistaus
+ Terjemahan bahasa Finlandia - Mikko95
+ Terjemahan bahasa Perancis - matthus
+ Terjemahan bahasa Jerman - GenosseFlosse, FloEdelmann, jensMF, leso-kn dan mkamp
+ Terjemahan bahasa Italia - igor-cali dan lrt84
+ Terjemahan bahasa Indonesia - hexatester
+ Terjemahan bahasa Polandia - wasikr7
+ Terjemahan bahasa Portugal - riuri (Brazil)
+ Terjemahan bahasa Swedia - nlssn
+
diff --git a/android_app/app/src/main/res/values-it/strings.xml b/android_app/app/src/main/res/values-it/strings.xml
index 275c1e2..6a3a663 100644
--- a/android_app/app/src/main/res/values-it/strings.xml
+++ b/android_app/app/src/main/res/values-it/strings.xml
@@ -22,9 +22,8 @@
Luogo
Data
Ora
- Ora (facoltativa)
- Compagni (facoltativi)
- Telefono (facoltativo)
+ Compagni
+ Telefono
Tipo di incontro
Al chiuso
All\'aperto
@@ -32,7 +31,7 @@
No
Sì
Non sicuro
- Note (facoltative)
+ Note
Nome
Familiare o amico intimo?
Selezionare
@@ -54,7 +53,7 @@
Voci cancellate
Diario dei Contatti è distribuito nella speranza che sia utile, ma SENZA ALCUNA GARANZIA; senza nemmeno garanzia implicita di COMMERCIABILITÀ o ADEGUATEZZA AD UNO FINE SPECIFICO. Questa pagina è utilizzata per informare i visitatori delle mie politiche di raccolta, uso e condivisione delle Informazioni Personali se qualcuno decide di utilizzare Diario dei Contatti. In breve, e poiché Diario dei Contatti non può connettersi ad internet, nessuna Informazione Personale verrà memorizzata o copiata al di fuori del dispositivo dell\'utente. Se decidi di utilizzare Diario dei Contatti, acconsenti alla raccolta (nessuna) ed all\'uso delle informazioni in accordo a questa informativa. Le Informazioni Personali raccolte da Diario dei Contatti vengono utilizzate per fornire il servizio. Come esplicitato sopra, non posso e quindi non userò né condividerò le tue informazioni con nessuno.
Raccolta ed uso delle informazioni
- L\'uso di Diario dei Contatti richiede l\'inserimento di alcune informazioni identificabili, ossia Nomi, Luoghie (opzionalmente) Numeri di telefono. Le informazioni richieste da Diario dei Contatti rimarranno nel tuo dispositivoe non sono raccolte da me in alcun modo.
+ L\'uso di Diario dei Contatti richiede l\'inserimento di alcune informazioni identificabili, ossia nomi e (opzionalmente) luoghie e numeri di telefono. Le informazioni richieste da Diario dei Contatti rimarranno nel tuo dispositivo e non sono raccolte da me in alcun modo.
Cookies e fornitori di servizi
I Cookie sono file con una piccola quantità di dati che sono comunemente usati come identificativi univoci anonimi. Essi sono trasmessi al tuo browser dai siti che visiti e memorizzati nella memoria interna del tuo dispositivo.\n\nDiario dei Contatti non usa alcun cookie, né proprietario né di terza parti.\n\nAllo stesso modo, nessun servizio è delegato a terze parti. Le informazioni che inserisci in Diario dei Contatti non lasciano mai il tuo dispositivo.
Sicurezza
@@ -67,4 +66,6 @@
Modifica
Voce duplicata
Voci duplicate
+ Grazie
+ Di
diff --git a/android_app/app/src/main/res/values-night/colors.xml b/android_app/app/src/main/res/values-night/colors.xml
new file mode 100644
index 0000000..fecb5a4
--- /dev/null
+++ b/android_app/app/src/main/res/values-night/colors.xml
@@ -0,0 +1,11 @@
+
+
+ #000000
+ #000000
+ #03DAC5
+ #333333
+ #000000
+ #1F1F1F
+ #03DAC5
+ #000000
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/values-night/dimens.xml b/android_app/app/src/main/res/values-night/dimens.xml
new file mode 100644
index 0000000..139a35c
--- /dev/null
+++ b/android_app/app/src/main/res/values-night/dimens.xml
@@ -0,0 +1,3 @@
+
+ 0dp
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/values-nl/strings.xml b/android_app/app/src/main/res/values-nl/strings.xml
index 4fe6f6b..10f9c60 100644
--- a/android_app/app/src/main/res/values-nl/strings.xml
+++ b/android_app/app/src/main/res/values-nl/strings.xml
@@ -1,71 +1,92 @@
- Contacten Dagboek
+ Contactdagboek
Instellingen
- Nieuw contact
+ Nieuwe contactpersoon
Nieuwe gebeurtenis
- Gebeurtenisnaam
+ Naam van gebeurtenis
Nee
Ja
Datum
- Tijd
- Plaats
- Metgezellen (optioneel)
- Denk je dat je de afstand behouden hebt?
+ Tijdstip
+ Locatie
+ Metgezellen
+ Denk je dat je afstand gehouden hebt?
Naam
Eigen familie of goede vriend?
- Denk je dat je de afstand behouden hebt?
- Telefoon (optioneel)
- Niet zeker
+ Denk je dat je afstand gehouden hebt?
+ Telefoonnummer
+ Weet ik niet
Vorm van contact
Binnenshuis
- Openlucht
- De dagboek is leeg
- Contact opgeslagen
+ Buitenshuis
+ Het dagboek is blanco
+ Contactpersoon opgeslagen
Gebeurtenis opgeslagen
- Bewerk gebeurtenis
- Contact bewerken
- Tijd (optioneel)
+ Gebeurtenis bewerken
+ Contactpersoon bewerken
Opties
- Vermelding verwijderd
- Vertel me wat je vindt van de app, of wat voor problemen ben je tegen gekomen
- Contact met ontwikkelaar
- Koop een koffie voor me
+ Item verwijderd
+ Vertel me wat je van de app vindt of wat voor problemen je bent tegengekomen
+ Contact opnemen met ontwikkelaar
+ Trakteer me op koffie
Met wie ben je vandaag geweest?
- Je contacten toevoegen aan de dagboek
- Kies alstublieft een optie
+ Contactpersonen toevoegen aan dagboek
+ Kies een optie
Verplicht veld
- Bewerken
+ Aanpassen
Verwijderen
Alarm aangepast
Voer een correcte datum in
Dagelijkse herinnering
- Kies tijdstip
- Toon alleen nauwe contacten
+ Kies een tijdstip
+ Alleen nauwe contactpersonen tonen
Meer
Instellingen
- Vermeldingen verwijderd
- " vermeldingen geselecteerd"
+ Items verwijderd
+ " items geselecteerd" van de app
Privacybeleid
- Contacten Dagboek wordt gepublisherd in de hoop dat het nuttig zal zijn, maar ZONDER ENIGE GARANTIE; zonder de impliciete garantie van VERKOOPBAARHEID of GESCHIKTHEID VOOR EEN BEPAALD DOEL. Deze pagina wordt gebruikt om bezoekers te informeren over mijn beleid met de verzameling, gebruik en openbaarmaking van persoonlijke informatie indien iemand heeft besloten om gebruik te maken van de Contacten Dagboek. Kortom, en omdat de Contacten Dagboek geen verbinding kan maken met het internet, worden persoonlijke informatie niet opgeslagen of gekopieerd buiten het apparaat van de gebruiker. Als u kiest voor het gebruiken van de Contacten Dagboek, ga je akkoord met het verzamelen (niet aan de orde) en gebruik van informatie met betrekking tot dit beleid. De persoonlijke informatie die de contactenlijst verzamelt wordt gebruikt voor het verstrekken van zijn service. Zoals ik al eerder heb gezegd, kan en zal ik uw informatie niet gebruiken en met niemand delen.
- Het gebruik van de contactenlijst vereist dat u bepaalde persoonlijk identificeerbare informatie invoert, namelijk Namen, Plaatsen en (optioneel) Telefoonnummers. De informatie die Contacten Dagboek aanvraag wordt bewaard op uw apparaat en wordt op geen enkele manier door mij opgehaald.
- Cookies zijn bestanden met een kleine hoeveelheid gegevens die vaak worden gebruikt als anonieme unieke Id\'s. Deze worden verzonden naar uw browser van de websites die u bezoekt en wordt opgeslagen in het interne geheugen van uw apparaat.\n\nContacten Dagboek gebruikt geen cookies, noch eerste noch derde partij.\n\n Op dezelfde manier wordt geen enkele service aan derden gedelegeerd. De informatie die u invoert in de contactenlijst zal nooit uw apparaat verlaten.
- Nogmaals, geen informatie die je toevoegt aan de contactenlijst zal nooit je apparaat verlaten. Dit feit kan altijd worden geëvalueerd door Contacten Dagboek\'s broncode te inspecteren, welke beschikbaar is op www.github.com/apozas/contactdiary. De veiligheid en integriteit ervan is dus gekoppeld aan de fysieke veiligheid en integriteit van uw apparaat, waar ik geen verantwoordelijkheid voor draag.
- Ik kan dit Privacybeleid van tijd tot tijd bijwerken. U wordt dus aangeraden om deze pagina periodiek te bekijken voor eventuele wijzigingen. Ik zal u op de hoogte brengen van eventuele wijzigingen door het nieuwe privacybeleid op deze pagina te plaatsen.\n\nDit beleid is van kracht vanaf 2020-09-09-08
- Als je vragen of suggesties hebt over dit privacybeleid, aarzel dan niet om mij contact op te nemen via contactdiary@alexpozas.com (bij voorkeur in het Engels).
- Wijzigingen in ons privacybeleid
+ Contactdagboek wordt uitgebracht in de hoop dat het nuttig zal zijn, maar ZONDER ENIGE GARANTIE; zonder de impliciete garantie van VERKOOPBAARHEID of GESCHIKTHEID VOOR EEN BEPAALD DOEL. Deze pagina wordt gebruikt om bezoekers te informeren over mijn beleid met de verzameling, gebruik en openbaarmaking van persoonlijke informatie indien iemand heeft besloten om gebruik te maken van het contactdagboek. Kortom, en omdat Contactdagboek geen verbinding kan maken met het internet, wordt persoonlijke informatie niet opgeslagen of gekopieerd buiten het apparaat van de gebruiker. Als je er voor kiest om de app te gebruiken, ga je akkoord met het verzamelen (niet aan de orde) en gebruik van informatie met betrekking tot dit beleid. De persoonlijke informatie die de contactpersonenlijst verzamelt wordt gebruikt voor het verstrekken van de dienst. Zoals ik al eerder heb gezegd, kan en zal ik je informatie niet gebruiken en met niemand delen.
+ Het gebruik van de contactpersonenlijst vereist dat je bepaalde persoonlijk identificeerbare informatie invoert, zoals namen en (optioneel) locaties en telefoonnummers. De informatie die de app opvraagt wordt bewaard op je apparaat en wordt op geen enkele manier door mij opgehaald.
+ Cookies zijn bestanden met een kleine hoeveelheid gegevens, die vaak worden gebruikt als anonieme unieke id\'s. Deze worden verzonden naar je browser aan de websites die je bezoekt en wordt opgeslagen op het interne geheugen van je apparaat.\n\nContactdagboek gebruikt geen cookies, noch eerste, noch derde partij.\n\n Op dezelfde manier wordt geen enkele dienst aan derden gedelegeerd. De informatie die je invoert op de contactpersonenlijst zal nooit je apparaat verlaten.
+ Nogmaals, informatie die je toevoegt aan de contactpersonenlijst zal nooit je apparaat verlaten. Dit feit kan altijd worden gecontroleerd door de broncode van Contactdagboek na te kijken, welke beschikbaar is op www.github.com/apozas/contactdiary. De veiligheid en integriteit ervan is dus gekoppeld aan de fysieke veiligheid en integriteit van je apparaat, waar ik geen verantwoordelijkheid voor draag.
+ Ik kan dit privacybeleid van tijd tot tijd bijwerken. Het is dus aanbevolen om deze pagina periodiek te bekijken en te controleren op eventuele wijzigingen. Ik zal je op de hoogte houden bij eventuele wijzigingen door het nieuwe privacybeleid op deze pagina te plaatsen.\n\nDit beleid is van kracht sinds 2020-09-08.
+ Als je vragen of suggesties hebt over dit privacybeleid, aarzel dan niet om contact met me op te nemen via contactdiary@alexpozas.com (bij voorkeur in het Engels).
+ Wijzigingen aan het privacybeleid
Verzamelen en gebruik van informatie
- Cookies en serviceproviders
+ Cookies en dienstproviders
Veiligheid
- Neem contact op
- Druk op (+) om contacten toe te voegen
- App versie
+ Contact opnemen
+ Druk op (+) om contactpersonen toe te voegen
+ Appversie
Beoordeel de app
- Als je de app handig vindt, beoordeel het dan en beoordeel het zodat het meer mensen kan bereiken die het misschien nuttig vinden
- Vermelding gedupliceerd
- Vermeldingen gedupliceerd
- Maak vandaag een kopie
- Selecteeren
- Notities (optioneel)
+ Als je de app graag gebruikt, beoordeel deze dan zodat de app meer mensen kan bereiken die hem misschien nuttig vinden
+ Item gekloond
+ Items gekloond
+ Kopie maken
+ Selecteren
+ Aantekeningen
+ Met dank aan
+ Over
+ Contactdagboek is begonnen als éénmansproject, maar heeft vele bijdragen vanuit de gemeenschap gehad. Mijn dank is groot aan iedereen op deze pagina.
+ Startschermsnelkoppelingen - GenosseFlosse
+ Nederlandse vertaling - Tonyinspace en Vistaus
+ Finse vertaling - Mikko95
+ Franse vertaling - matthus
+ Duitse vertaling - GenosseFlosse, FloEdelmann, jensMF, leso-kn en mkamp
+ Italiaanse vertaling - igor-cali en lrt84
+ Indonesische vertaling - hexatester
+ Poolse vertaling - wasikr7
+ Portugese vertaling - riuri (Brazilië)
+ Zweedse vertaling - nlssn
+ Thema
+ Licht
+ Donker
+ Systeemthema
+ Back-up en herstellen
+ Databank importeren
+ Een opgeslagen database laden
+ Database exporteren
+ Opslaan van de database in CSV-formaat
diff --git a/android_app/app/src/main/res/values-pl/strings.xml b/android_app/app/src/main/res/values-pl/strings.xml
new file mode 100644
index 0000000..786fd3c
--- /dev/null
+++ b/android_app/app/src/main/res/values-pl/strings.xml
@@ -0,0 +1,72 @@
+
+
+ Dziennik Kontaktów
+ Ustawienia
+ Nowy kontakt
+ Nowe wydarzenie
+ Nazwa wydarzenia
+ Nie
+ Tak
+ Data
+ Godzina
+ Miejsce
+ Towarzyszący
+ Myślisz, że zachowaliście dystans?
+ Imię
+ Krewny lub bliski znajomy?
+ Myślisz, że zachowaliście dystans?
+ Telefon
+ Nie wiem
+ Warunki spotkania
+ W pomieszczeniu
+ Na zewnątrz
+ Dziennik jest pusty
+ Spotkanie zapisane
+ Wydarzenie zapisane
+ Edytuj wydarzenie
+ Edytuj spotkanie
+ Opcje
+ Wpis usunięty
+ Daj znać, co sądzisz o programie albo poinformuj o napotkanych błędach
+ Kontakt z programistą
+ Kup mi kawę
+ Z kim się dziś spotkałeś?
+ Dodaj swoje spotkania do dziennika
+ Proszę wybrać opcję
+ Pole obowiązkowe
+ Edytuj
+ Usuń
+ Alarm zmieniony
+ Wpisz poprawną datę
+ Codzienne przypomnienie
+ Wybierz godzinę
+ Pokaż tylko bliskie kontakty
+ Więcej
+ Ustawienia
+ Wpisy usunięte
+ " wybranych wpisów"
+ Polityka prywatności
+ Dziennik Kontaktów jest rozprowadzany w nadziei, że będzie pomocny, ale BEZ JAKICHKOLWIEK GWARANCJI, nawet bez gwarancji ZBYWALNOŚCI lub DOPASOWANIA DO KONKRETNYCH CELÓW. Ta strona służy udzieleniu użytkownikom informacji na temat polityki zbierania i udostępniania danych osobowych, jeśli zdecydują się oni na użycie Dziennika Kontaktów. Ponieważ Dziennik Kontaktów nie może łączyć się z internetem, żadne dane nie będą przesłane ani przechowane poza urządzeniem. Jeśli decydujesz się używać Dziennika Kontaktów, zgadzasz się na to, że dane nie będą zbierane ani wykorzystane. Informacje, które zbierze Dziennik Kontaktów, są wykorzystane tylko wewnątrz aplikacji. Jak zostało jasno podkreślone powyżej, nie mogę i nie będę dzielił się informacjami z innymi podmiotami.
+ Korzystanie z Dziennika Kontaktów wymaga wprowadzenia pewnych informacji, a mianowicie nazw i (nieobowiązkowo) miejsc i numerów telefonów. Informacje, które Dziennik Kontaktów zbierze, zostaną zachowane na Twoim urządzeniu i nie będą w żaden sposób gromadzone poza nim.
+ Pliki cookie to pliki z niewielką ilością danych, które są powszechnie używane jako anonimowe niepowtarzalne identyfikatory. Są one wysyłane do Twojej przeglądarki z witryn, które odwiedzasz i są przechowywane w wewnętrznej pamięci urządzenia.\n\nDziennik Kontaktów nie używa żadnych plików cookie, ani własnych, ani stron trzecich.\n\nW ten sam sposób żadne informacje nie są przekazywane osobom trzecim. Informacje, które wprowadzasz do Dziennika Kontaktów, nigdy nie opuszczają Twojego urządzenia.
+ Jeszcze raz: żadne informacje, które wprowadzisz w Dzienniku Kontaktów, nie opuszczą Twojego urządzenia. Możesz się o tym przekonać, weryfikując kod źródłowy Dziennika Kontaktów na www.github.com/apozas/contactdiary. W związku z tym bezpieczeństwo i integralność danych całkowicie zależą od fizycznego zabezpieczenia Twojego urządzenia, za co nie odpowiadam.
+ Mogę aktualizować niniejszą Politykę Prywatności od czasu do czasu. Dlatego też zalecam okresowo przeglądać tę strony w celu śledzenia zmian. Powiadomię Cię o wszelkich zmianach, publikując nową Politykę prywatności na tej stronie.\n\nTa polityka wchodzi w życie 2020-09-08
+ Jeśli masz jakieś pytania lub sugestie dotyczące niniejszej Polityki Prywatności, nie wahaj się skontaktować ze mną pod adresem contactdiary@alexpozas.com (najlepiej w języku angielskim).
+ Zmiany w tej polityce prywatności
+ Gromadzenie i wykorzystywanie informacji
+ Pliki cookie i dostawcy usług
+ Bezpieczeństwo
+ Skontaktuj się ze mną
+ Naciśnij (+), aby rozpocząć dodawanie spotkań
+ Wersja aplikacji
+
+ Oceń aplikację
+ Jeśli podoba Ci się aplikacja, oceń ją i zrecenzuj, aby dotarła do większej liczby osób, którym może okazać się przydatna
+ Wpis powielony
+ Wpisy powielone
+ Utworzyć dziś kopię
+ Wybierz
+ Notatki
+ Dzięki
+ O
+
diff --git a/android_app/app/src/main/res/values-pt-rBR/strings.xml b/android_app/app/src/main/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..16e2a36
--- /dev/null
+++ b/android_app/app/src/main/res/values-pt-rBR/strings.xml
@@ -0,0 +1,83 @@
+
+
+ Diário de Contatos
+ Configurações
+ Novo contato
+ Novo evento
+ Nome do evento
+ Não
+ Sim
+ Data
+ Hora
+ Local
+ Companheiros
+ Você acha que manteve a distância?
+ Nome
+ Parente ou amigo próximo?
+ Vocês acham que mantiveram a distância?
+ Telefone
+ Não sei
+ Tipo de encontro
+ Lugar fechado
+ Ao ar livre
+ O diário está vazio
+ Contato salvo
+ Evento salvo
+ Editar evento
+ Editar contato
+ Opções
+ Entrada excluída
+ Diga-me o que pensa sobre o aplicativo, ou problemas que você tenha encontrado
+ Contatar o desenvolvedor
+ Pague-me um café
+ Com quem você esteve hoje?
+ Adicionar seus contatos ao diário
+ Por favor, selecione uma opção
+ Campo obrigatório
+ Editar
+ Excluir
+ Alarme modificado
+ Por favor, insira um horário correto
+ Lembrete diário
+ Selecionar horário
+ Mostrar apenas contatos próximos
+ Mais
+ Configurações
+ Entradas excluídas
+ " entradas selecionadas"
+ Política de privacidade
+ Diário de Contatos é distribuído na esperança de que seja útil, porém SEM QUALQUER GARANTIA; sem a garantia implícita de COMERCIALIZAÇÃO OU ADEQUAÇÃO A UM DETERMINADO PROPÓSITO. Esta página é usada para informar visitantes sobre minhas políticas de coleta, uso e revelação de Dados Pessoais se alguém decidir usar o Diário de Contatos. Em suma, dado que o Diário de Contatos não possui permissão de conexão à internet, nenhum Dado Pessoal será armazenado nem copiado para fora do dispositivo do usuário. Se você escolher usar o Diário de Contatos, você CONCORDA com a coleta (nenhuma) e uso dos dados relacionados a esta política. Os Dados Pessoais que o Diário de Contatos coleta são usados para prover este serviço. Como explicitado, eu não posso e portanto não utilizarei nem compartilharei seus dados com ninguém.
+ O uso do Diário de Contatos requer que você entre com certos dados pessoais identificáveis, a saber: nomes e (opcionalmente) lugares e números de telefone. Os dados que o Diário de Contatos requer serão armazenados no seu dispositivo e não coletados por mim de nenhuma maneira.
+ Cookies são arquivos com pequenas quantidades de dados que são utilizados normalmente como identificadores anônimos únicos. Eles são enviados ao seu navegador por websites que você visita e são armazenados na memória interna do seu dispositivo.\n\nO Diário de Contatos não usa nenhum cookie, nem de si nem de terceiros.\n\nDa mesma forma, nenhum serviço é delegado a terceiros. Os dados que você insere no Diário de Contatos nunca saem do seu dispositivo.
+ Novamente, nenhum dado que você insere no Diário de Contatos nunca deixa seu dispositivo. Este fato pode ser sempre verificado ao examinar o código fonte do Diário de Contatos, disponível em www.github.com/apozas/contactdiary. Portanto, sua segurança e integridade está ligada à segurança física e integridade do seu dispositivo, sobre as quais não tomo responsabilidade.
+ Posso atualizar esta Política de Privacidade de vez em quando. Assim, recomenda-se que você revise esta página periodicamente para quaisquer alterações. Eu lhe notificarei de qualquer alteração publicando a nova Política de Privacidade nesta página.\n\nEsta política é efetiva em 08 de setembro de 2020
+ Se você tiver alguma dúvida ou sugestão sobre esta Política de Privacidade, não hesite em contatar pelo contactdiary@alexpozas.com.
+ Alterações nessa política de privacidade
+ Coleta e uso de dados
+ Cookies e prestadores de serviço
+ Segurança
+ Contato
+ Pressione (+) para começar a adicionar contatos
+ Versão do aplicativo
+
+ Avaliar o aplicativo
+ Se você está gostando do aplicativo, por favor avalie para que possa chegar a mais pessoas que possam achá-lo útil
+ Entrada duplicada
+ Entradas duplicadas
+ Fazer uma cópia para hoje
+ Selecionar
+ Notas
+ Obrigado
+ Sobre
+ Embora o Diário de Contatos tenha começado como um projeto individual, ele se beneficiou de contribuições altruístas inestimáveis de muitas pessoas. Meus sinceros agradecimentos a todos nesta página.
+ Atalhos da tela inicial - GenosseFlosse
+ Tradução para Holandês - Tonyinspace e Vistaus
+ Tradução para Finlandês - Mikko95
+ Tradução para Francês - matthus
+ Tradução para Alemão - GenosseFlosse, FloEdelmann, jensMF, leso-kn e mkamp
+ Tradução para Italiano - igor-cali e lrt84
+ Tradução para Indonésio - hexatester
+ Tradução para Polonês - wasikr7
+ Tradução para Português - riuri (Brasil)
+ Tradução para Sueco - nlssn
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/values-sv/strings.xml b/android_app/app/src/main/res/values-sv/strings.xml
index b2f64f5..7a189f9 100644
--- a/android_app/app/src/main/res/values-sv/strings.xml
+++ b/android_app/app/src/main/res/values-sv/strings.xml
@@ -10,12 +10,12 @@
Datum
Tid
Plats
- Följeslagare (valfritt)
+ Följeslagare
Tror du att du höll avståndet?
Namn
Släkting eller nära vän?
Tror du att ni höll avståndet?
- Telefonnummer (valfritt)
+ Telefonnummer
Osäker
Typ av möte
Inomhus
@@ -25,7 +25,6 @@
Händelsen sparad
Redigera händelse
Redigera kontakt
- Tid (valfritt)
Inställningar
Inlägg raderat
Berätta vad du tycker om appen eller de problem du har stött på
@@ -48,7 +47,7 @@
" inlägg valda"
Sekretesspolicy
Kontaktdagboken distribueras i hopp om att det kommer att vara användbart, men UTAN NÅGON GARANTI; utan att ens den underförstådda garantin för SÄLJBARHET eller ANVÄNDNING FÖR ETT SPECIFIKT SYFTE. Denna sida är till för att för att informera besökare om min policy gällande insamling, användning, och utlämnande av personuppgifter om någon väljer att använda Kontaktdagboken. Kort sagt, eftersom Kontaktdagboken inte kan ansluta till internet, kommer ingen personlig information lagras eller kopieras utanför användarens enhet. Om du väljer att använda Kontaktdagboken, då godkänner du insamling (ingen) och användning av information i förhållande till denna policy. De personuppgifter som Kontaktdagboken samlar in används för att tillhandahålla sin service. Som uttryckligen nämnts ovan, jag kan inte och kommer därmed inte att använda eller dela din information med någon.
- Användningen av Kontaktdagboken kräver att du matar in viss personligt identifierbar information, nämligen namn, platser och (valfritt) telefonnummer. Den information som Kontaktdagboken begär kommer att lagras på din enhet och inte samlas in av mig på något sätt.
+ Användningen av Kontaktdagboken kräver att du matar in viss personligt identifierbar information, nämligen namn och (valfritt) platser och telefonnummer. Den information som Kontaktdagboken begär kommer att lagras på din enhet och inte samlas in av mig på något sätt.
Cookies är filer med en liten mängd data som ofta används som anonyma unika identifierare. Dessa skickas till din webbläsare från de webbplatser som du besöker och lagras på din enhets interna minne.\n\nKontaktdagboken använder inga cookies, varken första part eller tredje part.\n\nPå samma sätt är ingen tjänst delegerad till tredje part. Informationen du matar in i Kontaktdagboken lämnar aldrig din enhet.
Återigen, ingen information du matar in till Kontaktdagboken lämnar någonsin din enhet. Detta faktum kan alltid utvärderas genom att inspektera Kontaktdagbokens källkod, som finns på www.github.com/apozas/contactdiary. Således är dess säkerhet och integritet kopplad till den fysiska säkerheten och integriteten hos din enhet, som jag inte tar något ansvar för.
Jag kan komma att uppdatera denna sekretesspolicy i framtiden. Således uppmanas du att granska denna sida regelbundet för eventuella ändringar. Jag kommer att meddela dig om eventuella ändringar genom att publicera den nya sekretesspolicyn på denna sida.\n\nDenna policy gäller från och med 2020-09-08
@@ -67,5 +66,7 @@
Inlägg duplicerade
Skapa en kopia idag
Välj
- Anteckningar (valfritt)
+ Anteckningar
+ Tack
+ Handla om
diff --git a/android_app/app/src/main/res/values/arrays.xml b/android_app/app/src/main/res/values/arrays.xml
new file mode 100644
index 0000000..34e9d74
--- /dev/null
+++ b/android_app/app/src/main/res/values/arrays.xml
@@ -0,0 +1,14 @@
+
+
+
+ - @string/theme_system
+ - @string/theme_light
+ - @string/theme_dark
+
+
+
+ - System
+ - Light
+ - Dark
+
+
\ No newline at end of file
diff --git a/android_app/app/src/main/res/values/colors.xml b/android_app/app/src/main/res/values/colors.xml
index 7433017..bfe34e4 100644
--- a/android_app/app/src/main/res/values/colors.xml
+++ b/android_app/app/src/main/res/values/colors.xml
@@ -4,4 +4,8 @@
#006C63
#03DAC5
#DADADA
+ #FAFAFA
+ #006C63
+ #FFFFFF
+ #009688
\ No newline at end of file
diff --git a/android_app/app/src/main/res/values/dimens.xml b/android_app/app/src/main/res/values/dimens.xml
index 125df87..d134acf 100644
--- a/android_app/app/src/main/res/values/dimens.xml
+++ b/android_app/app/src/main/res/values/dimens.xml
@@ -1,3 +1,5 @@
- 16dp
+ 16dp
+ 16dp
+ 12dp
\ No newline at end of file
diff --git a/android_app/app/src/main/res/values/strings.xml b/android_app/app/src/main/res/values/strings.xml
index 9c5da96..2190382 100644
--- a/android_app/app/src/main/res/values/strings.xml
+++ b/android_app/app/src/main/res/values/strings.xml
@@ -10,12 +10,12 @@
Date
Time
Place
- Companions (optional)
+ Companions
Do you think you kept the distance?
Name
Relative or close friend?
Do you think you kept the distance?
- Phone (optional)
+ Phone
Not sure
Encounter type
Indoors
@@ -25,7 +25,6 @@
Event saved
Edit event
Edit contact
- Time (optional)
Options
Entry deleted
Tell me what you think about the app, or problems you have encountered
@@ -52,7 +51,7 @@
" entries selected"
Privacy policy
Contact Diary is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information if anyone decided to use Contact Diary. In short, and since Contact Diary cannot connect to the internet, no Personal Information will be stored nor copied outside the user\'s device. If you choose to use Contact Diary, then you agree to the collection (none) and use of information in relation to this policy. The Personal Information that Contact Diary collects is used for providing its service. As made explicit above, I cannot and thus will not use nor share your information with anyone.
- The use of Contact Diary requires that you input certain personally identifiable information, namely Names, Places and (optionally) Phone numbers. The information that Contact Diary requests will be retained on your device and is not collected by me in any way.
+ The use of Contact Diary requires that you input certain personally identifiable information, namely names and (optionally) places and phone numbers. The information that Contact Diary requests will be retained on your device and is not collected by me in any way.
Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device\'s internal memory.\n\nContact Diary does not use any cookies, neither first-party nor third-party.\n\nIn the same way, no service is delegated to third parties. The information you input into Contact Diary never leaves your device.
Again, no information you input to Contact Diary ever leaves your device. This fact can be always evaluated by inspecting Contact Diary\'s source code, which is available at www.github.com/apozas/contactdiary. Thus, its security and integrity is linked to the physical security and integrity of your device, of which I take no responsibility.
I may update this Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page.\n\nThis policy is effective as of 2020-09-08
@@ -72,5 +71,32 @@
Entries duplicated
Make a copy today
Select
- Notes (optional)
+ Notes
+ Thanks
+ About
+ While Contact Diary started as a solo project, it has benefited from invaluable altruistic contributions from many people. My honest thanks to everyone in this page.
+ Homescreen shortcuts - GenosseFlosse
+ Dutch translation - Tonyinspace and Vistaus
+ Finnish translation - Mikko95
+ French translation - matthus
+ German translation - GenosseFlosse, FloEdelmann, jensMF, leso-kn and mkamp
+ Italian translation - igor-cali and lrt84
+ Indonesian translation - hexatester
+ Polish translation - wasikr7
+ Portuguese translation - riuri (Brazil)
+ Swedish translation - nlssn
+ Theme
+ Light
+ Dark
+ Follow system
+ Backup and restore
+ Import database
+ Load a saved database
+ Export database
+ Save the database in CSV format
+ Database saved
+ There is a problem with the database
+ Database loaded
+ The specified file was not found
+ Select the database to import
\ No newline at end of file
diff --git a/android_app/app/src/main/res/values/styles.xml b/android_app/app/src/main/res/values/styles.xml
index 3f96e47..f15a6c3 100644
--- a/android_app/app/src/main/res/values/styles.xml
+++ b/android_app/app/src/main/res/values/styles.xml
@@ -1,12 +1,13 @@
-