add bottomsheet navigation
1
app/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
||||||
/build
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileSdkVersion 28
|
|
||||||
defaultConfig {
|
|
||||||
applicationId "com.example.hochi.nextcompanion"
|
|
||||||
minSdkVersion 15
|
|
||||||
targetSdkVersion 28
|
|
||||||
versionCode 9
|
|
||||||
versionName "0.1.7.2"
|
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
|
||||||
}
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
minifyEnabled false
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
||||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
|
|
||||||
implementation 'com.android.support:design:28.0.0'
|
|
||||||
testImplementation 'junit:junit:4.12'
|
|
||||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
|
||||||
}
|
|
||||||
21
app/proguard-rules.pro
vendored
|
|
@ -1,21 +0,0 @@
|
||||||
# Add project specific ProGuard rules here.
|
|
||||||
# You can control the set of applied configuration files using the
|
|
||||||
# proguardFiles setting in build.gradle.
|
|
||||||
#
|
|
||||||
# For more details, see
|
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
||||||
|
|
||||||
# If your project uses WebView with JS, uncomment the following
|
|
||||||
# and specify the fully qualified class name to the JavaScript interface
|
|
||||||
# class:
|
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
||||||
# public *;
|
|
||||||
#}
|
|
||||||
|
|
||||||
# Uncomment this to preserve the line number information for
|
|
||||||
# debugging stack traces.
|
|
||||||
#-keepattributes SourceFile,LineNumberTable
|
|
||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
|
||||||
# hide the original source file name.
|
|
||||||
#-renamesourcefileattribute SourceFile
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package com.example.hochi.nextcompanion;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.support.test.InstrumentationRegistry;
|
|
||||||
import android.support.test.runner.AndroidJUnit4;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instrumented test, which will execute on an Android device.
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class ExampleInstrumentedTest {
|
|
||||||
@Test
|
|
||||||
public void useAppContext() {
|
|
||||||
// Context of the app under test.
|
|
||||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
|
||||||
|
|
||||||
assertEquals("com.example.hochi.nextcompanion", appContext.getPackageName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="com.example.hochi.nextcompanion">
|
|
||||||
|
|
||||||
<!-- To auto-complete the email text field in the login form with the user's emails -->
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:allowBackup="true"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
|
||||||
android:supportsRtl="true"
|
|
||||||
android:theme="@style/AppTheme">
|
|
||||||
<activity
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/AppTheme.NoActionBar">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
<activity
|
|
||||||
android:name=".LoginActivity"
|
|
||||||
android:label="@string/title_activity_login" />
|
|
||||||
<activity android:name=".RentActivity"
|
|
||||||
android:label="@string/title_activity_rent">
|
|
||||||
<meta-data
|
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
|
||||||
android:value=".MainActivity" />
|
|
||||||
<intent-filter android:label="@string/action_open_with">
|
|
||||||
<action android:name="android.intent.action.VIEW" />
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
|
||||||
<data android:scheme="http"
|
|
||||||
android:host="nxtb.it"
|
|
||||||
android:pathPrefix="/" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
<activity android:name=".ReturnActivity"
|
|
||||||
android:label="@string/title_activity_return">
|
|
||||||
<meta-data
|
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
|
||||||
android:value=".MainActivity" />
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
|
|
||||||
</manifest>
|
|
||||||
|
Before Width: | Height: | Size: 18 KiB |
|
|
@ -1,5 +0,0 @@
|
||||||
package com.example.hochi.nextcompanion;
|
|
||||||
|
|
||||||
interface AsyncTaskCallbacks<T> {
|
|
||||||
void onTaskComplete(T response);
|
|
||||||
}
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
package com.example.hochi.nextcompanion;
|
|
||||||
|
|
||||||
import android.animation.Animator;
|
|
||||||
import android.animation.AnimatorListenerAdapter;
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.view.KeyEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.View.OnClickListener;
|
|
||||||
import android.view.inputmethod.EditorInfo;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A login screen that offers login via phone number/pin.
|
|
||||||
*/
|
|
||||||
public class LoginActivity extends AppCompatActivity implements AsyncTaskCallbacks<String> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Keep track of the login task to ensure we can cancel it if requested.
|
|
||||||
*/
|
|
||||||
private RequestHandler mAuthTask = null;
|
|
||||||
|
|
||||||
// UI references.
|
|
||||||
private TextView mPhoneView;
|
|
||||||
private EditText mPinView;
|
|
||||||
private View mProgressView;
|
|
||||||
private View mLoginFormView;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_login);
|
|
||||||
// Set up the login form.
|
|
||||||
mPhoneView = findViewById(R.id.phone);
|
|
||||||
|
|
||||||
mPinView = findViewById(R.id.pin);
|
|
||||||
mPinView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
|
|
||||||
if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
|
|
||||||
attemptLogin();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Button mPhoneSignInButton = findViewById(R.id.phone_sign_in_button);
|
|
||||||
mPhoneSignInButton.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
attemptLogin();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mLoginFormView = findViewById(R.id.login_form);
|
|
||||||
mProgressView = findViewById(R.id.login_progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attempts to sign in or register the account specified by the login form.
|
|
||||||
* If there are form errors (invalid phone number, missing fields, etc.), the
|
|
||||||
* errors are presented and no actual login attempt is made.
|
|
||||||
*/
|
|
||||||
private void attemptLogin() {
|
|
||||||
if (mAuthTask != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset errors.
|
|
||||||
mPhoneView.setError(null);
|
|
||||||
mPinView.setError(null);
|
|
||||||
|
|
||||||
// Store values at the time of the login attempt.
|
|
||||||
String phone = mPhoneView.getText().toString();
|
|
||||||
String pin = mPinView.getText().toString();
|
|
||||||
String[] credentials = {
|
|
||||||
"apikey=", getString(R.string.apikey),
|
|
||||||
"mobile=", mPhoneView.getText().toString(),
|
|
||||||
"pin=", mPinView.getText().toString()
|
|
||||||
};
|
|
||||||
|
|
||||||
boolean cancel = false;
|
|
||||||
View focusView = null;
|
|
||||||
|
|
||||||
// Check for a valid pin, if the user entered one.
|
|
||||||
if (TextUtils.isEmpty(pin)) {
|
|
||||||
mPinView.setError(getString(R.string.error_field_required));
|
|
||||||
focusView = mPinView;
|
|
||||||
cancel = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for a valid phone address.
|
|
||||||
if (TextUtils.isEmpty(phone)) {
|
|
||||||
mPhoneView.setError(getString(R.string.error_field_required));
|
|
||||||
focusView = mPhoneView;
|
|
||||||
cancel = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cancel) {
|
|
||||||
// There was an error; don't attempt login and focus the first
|
|
||||||
// form field with an error.
|
|
||||||
focusView.requestFocus();
|
|
||||||
} else {
|
|
||||||
// Show a progress spinner, and kick off a background task to
|
|
||||||
// perform the user login attempt.
|
|
||||||
showProgress(true);
|
|
||||||
mAuthTask = new RequestHandler(this, "POST",
|
|
||||||
"api/login.json", credentials);
|
|
||||||
mAuthTask.execute((Void) null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the progress UI and hides the login form.
|
|
||||||
*/
|
|
||||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
|
|
||||||
private void showProgress(final boolean show) {
|
|
||||||
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
|
|
||||||
// for very easy animations. If available, use these APIs to fade-in
|
|
||||||
// the progress spinner.
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
|
|
||||||
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
|
|
||||||
|
|
||||||
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
|
|
||||||
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
|
|
||||||
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
|
|
||||||
mProgressView.animate().setDuration(shortAnimTime).alpha(
|
|
||||||
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
|
|
||||||
@Override
|
|
||||||
public void onAnimationEnd(Animator animation) {
|
|
||||||
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// The ViewPropertyAnimator APIs are not available, so simply show
|
|
||||||
// and hide the relevant UI components.
|
|
||||||
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
|
|
||||||
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTaskComplete(String response) {
|
|
||||||
//Callback called when RequestHandler finished request
|
|
||||||
if (!response.isEmpty()) {
|
|
||||||
try {
|
|
||||||
JSONObject jObject = new JSONObject(response);
|
|
||||||
JSONObject userObject = jObject.getJSONObject("user");
|
|
||||||
String loginkey = userObject.getString("loginkey");
|
|
||||||
SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
|
|
||||||
SharedPreferences.Editor editor = sharedPref.edit();
|
|
||||||
editor.putString("loginKey", loginkey);
|
|
||||||
editor.apply();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
finish();
|
|
||||||
} else {
|
|
||||||
mPinView.setError(getString(R.string.error_incorrect_pin));
|
|
||||||
mPinView.requestFocus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
package com.example.hochi.nextcompanion;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.design.widget.FloatingActionButton;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.support.v7.widget.Toolbar;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ArrayAdapter;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity implements AsyncTaskCallbacks<String> {
|
|
||||||
private RequestHandler getBikesTask = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
//now this "every android activity" stuff
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_main);
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
|
||||||
setSupportActionBar(toolbar);
|
|
||||||
final Context context = this;
|
|
||||||
|
|
||||||
//Floating Button
|
|
||||||
FloatingActionButton fab = findViewById(R.id.fab);
|
|
||||||
fab.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
Intent intent = new Intent(context, RentActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onStart() {
|
|
||||||
super.onStart();
|
|
||||||
//pre-condition: Is there a login key?
|
|
||||||
SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
|
|
||||||
String defaultValue = "nokey";
|
|
||||||
String loginKey = sharedPref.getString("loginKey", defaultValue);
|
|
||||||
//if not, go to LoginActivity
|
|
||||||
if (loginKey.equals("nokey")) {
|
|
||||||
Intent intent = new Intent(this, LoginActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
reloadBikeList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
|
||||||
// Inflate the menu; this adds items to the action bar if it is present.
|
|
||||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
// Handle action bar item clicks here. The action bar will
|
|
||||||
// automatically handle clicks on the Home/Up button, so long
|
|
||||||
// as you specify a parent activity in AndroidManifest.xml.
|
|
||||||
int id = item.getItemId();
|
|
||||||
|
|
||||||
|
|
||||||
//noinspection SimplifiableIfStatement
|
|
||||||
if (id == R.id.action_logout) {
|
|
||||||
SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
|
|
||||||
SharedPreferences.Editor editor = sharedPref.edit();
|
|
||||||
editor.remove("loginKey");
|
|
||||||
editor.apply();
|
|
||||||
Intent intent = new Intent(this, LoginActivity.class);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id == R.id.action_map) {
|
|
||||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.map_url)));
|
|
||||||
startActivity(browserIntent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void reloadBikeList() {
|
|
||||||
//get loginkey
|
|
||||||
SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
|
|
||||||
String defaultValue = "nokey";
|
|
||||||
String loginKey = sharedPref.getString("loginKey", defaultValue);
|
|
||||||
|
|
||||||
String[] params = {
|
|
||||||
"apikey=", getString(R.string.apikey),
|
|
||||||
"loginkey=", loginKey
|
|
||||||
};
|
|
||||||
|
|
||||||
getBikesTask = new RequestHandler(this, "POST",
|
|
||||||
"api/getOpenRentals.json", params);
|
|
||||||
getBikesTask.execute((Void) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTaskComplete(String response) {
|
|
||||||
//Callback called when RequestHandler finished request
|
|
||||||
final Context context = this;
|
|
||||||
if (!response.isEmpty()) {
|
|
||||||
final ArrayList<String> list = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
JSONObject jObject = new JSONObject(response);
|
|
||||||
JSONArray bikesArray = jObject.getJSONArray("rentalCollection");
|
|
||||||
for (int i = 0; i < bikesArray.length(); i++) {
|
|
||||||
String entry;
|
|
||||||
JSONObject bike = bikesArray.getJSONObject(i);
|
|
||||||
entry = "Bike " + bike.getString("bike")
|
|
||||||
+ " with lock code " + bike.getString("code");
|
|
||||||
list.add(entry);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create and fill list
|
|
||||||
final ListView listview = findViewById(R.id.listview);
|
|
||||||
final ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
|
|
||||||
android.R.layout.simple_list_item_1, list);
|
|
||||||
listview.setAdapter(adapter);
|
|
||||||
|
|
||||||
//Print indicator if empty
|
|
||||||
TextView tv = findViewById(R.id.noBikes);
|
|
||||||
if(list.isEmpty()) tv.setVisibility(View.VISIBLE);
|
|
||||||
else tv.setVisibility(View.INVISIBLE);
|
|
||||||
|
|
||||||
try {
|
|
||||||
final JSONObject jObject = new JSONObject(response);
|
|
||||||
final JSONArray bikesArray = jObject.getJSONArray("rentalCollection");
|
|
||||||
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
|
|
||||||
Intent intent = new Intent(context, ReturnActivity.class);
|
|
||||||
try {
|
|
||||||
JSONObject bike = bikesArray.getJSONObject(position);
|
|
||||||
String bID = bike.getString("bike");
|
|
||||||
String stID = bike.getString("start_place");
|
|
||||||
String lockE = bike.getString("electric_lock");
|
|
||||||
String[] bikeArray = {bID, stID, lockE};
|
|
||||||
intent.putExtra("bike", bikeArray);
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
} catch (JSONException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//TODO: implement error handling
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
package com.example.hochi.nextcompanion;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.w3c.dom.Text;
|
|
||||||
|
|
||||||
public class RentActivity extends AppCompatActivity implements AsyncTaskCallbacks<String> {
|
|
||||||
private RequestHandler rentRequestTask = null;
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_rent);
|
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
||||||
Button mRentSubmitButton = findViewById(R.id.rent_submit_button);
|
|
||||||
mRentSubmitButton.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
rentRequest();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
|
||||||
Uri data = intent.getData();
|
|
||||||
|
|
||||||
if (data != null) {
|
|
||||||
String bikeID = data.toString().substring(15);
|
|
||||||
((TextView) findViewById(R.id.bike_id)).setText(bikeID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rentRequest() {
|
|
||||||
//Prepare request to rent bike
|
|
||||||
TextView mBikeInput;
|
|
||||||
mBikeInput = findViewById(R.id.bike_id);
|
|
||||||
String bikeID = mBikeInput.getText().toString();
|
|
||||||
//get loginkey
|
|
||||||
SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
|
|
||||||
String defaultValue = "nokey";
|
|
||||||
String loginKey = sharedPref.getString("loginKey", defaultValue);
|
|
||||||
|
|
||||||
String[] params = {
|
|
||||||
"apikey=", getString(R.string.apikey),
|
|
||||||
"loginkey=", loginKey,
|
|
||||||
"bike=", bikeID
|
|
||||||
};
|
|
||||||
|
|
||||||
rentRequestTask = new RequestHandler(this, "POST",
|
|
||||||
"api/rent.json", params);
|
|
||||||
rentRequestTask.execute((Void) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTaskComplete(String response) {
|
|
||||||
//get back to main activity
|
|
||||||
//TODO: *any* response handling
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
package com.example.hochi.nextcompanion;
|
|
||||||
|
|
||||||
import android.os.AsyncTask;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
|
|
||||||
public class RequestHandler extends AsyncTask<Void, Void, String> {
|
|
||||||
|
|
||||||
private String mHTTPmethod;
|
|
||||||
private String mEndpoint;
|
|
||||||
private AsyncTaskCallbacks<String> callback;
|
|
||||||
private String[] mCredentials;
|
|
||||||
|
|
||||||
RequestHandler(AsyncTaskCallbacks<String> act, String HTTPmethod,
|
|
||||||
String endpoint, String[] credentials) {
|
|
||||||
mHTTPmethod = HTTPmethod;
|
|
||||||
mEndpoint = endpoint;
|
|
||||||
mCredentials = credentials;
|
|
||||||
callback = act;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String doInBackground(Void... params) {
|
|
||||||
StringBuilder response = new StringBuilder();
|
|
||||||
StringBuilder urlParameters = new StringBuilder();
|
|
||||||
int i=0;
|
|
||||||
while (i<mCredentials.length) {
|
|
||||||
urlParameters.append("&").append(mCredentials[i])
|
|
||||||
.append(URLEncoder.encode(mCredentials[i+1]));
|
|
||||||
i=i+2;
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpURLConnection connection = null;
|
|
||||||
try {
|
|
||||||
|
|
||||||
//Create connection
|
|
||||||
URL url = new URL("https://api.nextbike.net/" + mEndpoint);
|
|
||||||
connection = (HttpURLConnection) url.openConnection();
|
|
||||||
connection.setRequestMethod(mHTTPmethod);
|
|
||||||
if(mHTTPmethod.equals("POST")) {
|
|
||||||
connection.setRequestProperty("Content-Type",
|
|
||||||
"application/x-www-form-urlencoded");
|
|
||||||
|
|
||||||
connection.setRequestProperty("Content-Length", "" +
|
|
||||||
Integer.toString(urlParameters.toString().getBytes().length));
|
|
||||||
connection.setRequestProperty("Content-Language", "en-US");
|
|
||||||
|
|
||||||
connection.setUseCaches(false);
|
|
||||||
connection.setDoInput(true);
|
|
||||||
connection.setDoOutput(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Send request
|
|
||||||
DataOutputStream wr = new DataOutputStream (
|
|
||||||
connection.getOutputStream ());
|
|
||||||
wr.writeBytes (urlParameters.toString());
|
|
||||||
wr.flush ();
|
|
||||||
wr.close ();
|
|
||||||
|
|
||||||
//Get Response
|
|
||||||
InputStream is = connection.getInputStream();
|
|
||||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
|
|
||||||
String line;
|
|
||||||
while((line = rd.readLine()) != null) {
|
|
||||||
response.append(line);
|
|
||||||
response.append('\r');
|
|
||||||
}
|
|
||||||
rd.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if(connection != null) {
|
|
||||||
connection.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(final String response) {
|
|
||||||
//TODO: reimplement progress or remove support for it
|
|
||||||
callback.onTaskComplete(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCancelled() {
|
|
||||||
//TODO: proper handling if needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
package com.example.hochi.nextcompanion;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.support.v7.app.AppCompatActivity;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
public class ReturnActivity extends AppCompatActivity implements AsyncTaskCallbacks<String> {
|
|
||||||
private String[] bikeArray;
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
setContentView(R.layout.activity_return);
|
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
|
||||||
|
|
||||||
|
|
||||||
Intent intent = getIntent();
|
|
||||||
bikeArray = intent.getStringArrayExtra("bike");
|
|
||||||
|
|
||||||
//if GPS and electric lock, show the instruction
|
|
||||||
TextView tv = findViewById(R.id.gps_info);
|
|
||||||
LinearLayout la = findViewById(R.id.return_form_container);
|
|
||||||
if(bikeArray[2].equals("true")) {
|
|
||||||
tv.setVisibility(View.VISIBLE);
|
|
||||||
la.setVisibility(View.INVISIBLE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
la.setVisibility(View.VISIBLE);
|
|
||||||
tv.setVisibility(View.INVISIBLE);
|
|
||||||
Button mReturnSubmitButton = findViewById(R.id.return_submit_button);
|
|
||||||
mReturnSubmitButton.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
returnRequest();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void returnRequest() {
|
|
||||||
TextView mStationInput;
|
|
||||||
mStationInput = findViewById(R.id.return_station_id);
|
|
||||||
String stationID = mStationInput.getText().toString();
|
|
||||||
//get loginkey
|
|
||||||
SharedPreferences sharedPref = getSharedPreferences("persistence", MODE_PRIVATE);
|
|
||||||
String defaultValue = "nokey";
|
|
||||||
String loginKey = sharedPref.getString("loginKey", defaultValue);
|
|
||||||
|
|
||||||
String[] params = {
|
|
||||||
"apikey=", getString(R.string.apikey),
|
|
||||||
"bike=", bikeArray[0],
|
|
||||||
"loginkey=", loginKey,
|
|
||||||
"station=", stationID,
|
|
||||||
"comment=", ""
|
|
||||||
};
|
|
||||||
RequestHandler returnRequestTask = new RequestHandler(this, "POST",
|
|
||||||
"api/return.json", params);
|
|
||||||
returnRequestTask.execute((Void) null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onTaskComplete(String response) {
|
|
||||||
//get back to main activity
|
|
||||||
//TODO: *any* response handling
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#ffffff"
|
|
||||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
|
||||||
</vector>
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
|
||||||
tools:context=".LoginActivity">
|
|
||||||
|
|
||||||
<!-- Login progress -->
|
|
||||||
<ProgressBar
|
|
||||||
android:id="@+id/login_progress"
|
|
||||||
style="?android:attr/progressBarStyleLarge"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:visibility="gone" />
|
|
||||||
|
|
||||||
<ScrollView
|
|
||||||
android:id="@+id/login_form"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/phone_login_form"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<android.support.design.widget.TextInputLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/phone"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="@string/prompt_phone"
|
|
||||||
android:inputType="phone"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
</android.support.design.widget.TextInputLayout>
|
|
||||||
|
|
||||||
<android.support.design.widget.TextInputLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/pin"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="@string/prompt_pin"
|
|
||||||
android:imeActionId="6"
|
|
||||||
android:imeActionLabel="@string/action_sign_in_short"
|
|
||||||
android:imeOptions="actionUnspecified"
|
|
||||||
android:inputType="numberPassword"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
</android.support.design.widget.TextInputLayout>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/phone_sign_in_button"
|
|
||||||
style="?android:textAppearanceSmall"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="@string/action_sign_in"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".MainActivity">
|
|
||||||
|
|
||||||
<android.support.design.widget.AppBarLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:theme="@style/AppTheme.AppBarOverlay">
|
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
|
||||||
android:id="@+id/toolbar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="?attr/actionBarSize"
|
|
||||||
android:background="?attr/colorPrimary"
|
|
||||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
|
||||||
|
|
||||||
</android.support.design.widget.AppBarLayout>
|
|
||||||
|
|
||||||
<include layout="@layout/content_main" />
|
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
|
||||||
android:id="@+id/fab"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom|end"
|
|
||||||
android:layout_margin="@dimen/fab_margin"
|
|
||||||
android:src="@drawable/ic_add_white_24dp" />
|
|
||||||
|
|
||||||
</android.support.design.widget.CoordinatorLayout>
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
|
||||||
tools:context=".RentActivity">
|
|
||||||
<ScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/rent_form"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<android.support.design.widget.TextInputLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/bike_id"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="@string/prompt_bike_id"
|
|
||||||
android:inputType="number"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
</android.support.design.widget.TextInputLayout>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/rent_submit_button"
|
|
||||||
style="?android:textAppearanceSmall"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="@string/action_rent_submit"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:gravity="center_horizontal"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
|
||||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
|
||||||
android:paddingTop="@dimen/activity_vertical_margin"
|
|
||||||
tools:context=".ReturnActivity">
|
|
||||||
<ScrollView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/return_form"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/return_form_container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
<android.support.design.widget.TextInputLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/return_station_id"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:hint="@string/prompt_return_station_id"
|
|
||||||
android:inputType="number"
|
|
||||||
android:maxLines="1"
|
|
||||||
android:singleLine="true" />
|
|
||||||
|
|
||||||
</android.support.design.widget.TextInputLayout>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/return_submit_button"
|
|
||||||
style="?android:textAppearanceSmall"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:text="@string/action_return_submit"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/gps_info"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:text="@string/indicator_electronic_lock" />
|
|
||||||
</LinearLayout>
|
|
||||||
</ScrollView>
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
tools:context=".MainActivity"
|
|
||||||
tools:showIn="@layout/activity_main">
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/noBikes"
|
|
||||||
android:gravity="center"
|
|
||||||
android:textSize="20sp"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:text="@string/indicator_no_bikes" />
|
|
||||||
|
|
||||||
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/listview"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
tools:context="com.example.hochi.nextcompanion.MainActivity">
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_map"
|
|
||||||
android:orderInCategory="100"
|
|
||||||
android:title="@string/action_map"
|
|
||||||
app:showAsAction="never" />
|
|
||||||
<item
|
|
||||||
android:id="@+id/action_logout"
|
|
||||||
android:orderInCategory="100"
|
|
||||||
android:title="@string/action_logout"
|
|
||||||
app:showAsAction="never" />
|
|
||||||
</menu>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
|
|
@ -1,30 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<!-- human readables -->
|
|
||||||
<string name="app_name">NextCompanion</string>
|
|
||||||
|
|
||||||
<string name="action_logout">Ausloggen</string>
|
|
||||||
<string name="title_activity_login">Anmelden</string>
|
|
||||||
<string name="prompt_phone">Mobiltelefonnummer</string>
|
|
||||||
<string name="prompt_pin">Pin</string>
|
|
||||||
<string name="action_sign_in">Anmelden</string>
|
|
||||||
<string name="action_sign_in_short">Anmelden</string>
|
|
||||||
<string name="error_invalid_email">Telefonnummer ist inkorrekt</string>
|
|
||||||
<string name="error_incorrect_pin">Pin oder Telefonnummer ist inkorrekt</string>
|
|
||||||
<string name="error_field_required">Feld ist erforderlich</string>
|
|
||||||
<string name="title_activity_rent">Rad ausleihen</string>
|
|
||||||
<string name="prompt_bike_id">Fahrrad-ID eingeben</string>
|
|
||||||
<string name="action_rent_submit">Ausleihen</string>
|
|
||||||
<string name="prompt_return_station_id">Nummer der Rückgabestation</string>
|
|
||||||
<string name="action_return_submit">Rückgabe</string>
|
|
||||||
<string name="title_activity_return">Fahrrad zurückgeben</string>
|
|
||||||
<string name="action_map">Karte</string>
|
|
||||||
<string name="indicator_no_bikes">Keine Räder geliehen…</string>
|
|
||||||
<string name="indicator_electronic_lock">Dieses Rad ein elektronisches Schloss. Zur Rückgabe bitte das Schloss schließen.</string>
|
|
||||||
|
|
||||||
<!-- machine readables -->
|
|
||||||
<string name="apikey">3IaBlP9OZw14dvES</string>
|
|
||||||
<string name="map_url"><![CDATA[https://nextbike.net/reservation/?lat=50.7086&lng=10.6348&zoom=5&maponly=1]]></string>
|
|
||||||
<string name="isLoggedIn">persistence</string>
|
|
||||||
<string name="action_open_with">Ausleihen mit NextCompanion</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="colorPrimary">#3F51B5</color>
|
|
||||||
<color name="colorPrimaryDark">#303F9F</color>
|
|
||||||
<color name="colorAccent">#9c274f</color>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
<resources>
|
|
||||||
<dimen name="fab_margin">16dp</dimen>
|
|
||||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="ic_launcher_background">#000000</color>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<resources>
|
|
||||||
<!-- human readables -->
|
|
||||||
<string name="app_name">NextCompanion</string>
|
|
||||||
|
|
||||||
<string name="action_logout">Logout</string>
|
|
||||||
<string name="title_activity_login">Sign in</string>
|
|
||||||
<string name="prompt_phone">Phone number</string>
|
|
||||||
<string name="prompt_pin">Pin</string>
|
|
||||||
<string name="action_sign_in">Sign in</string>
|
|
||||||
<string name="action_sign_in_short">Sign in</string>
|
|
||||||
<string name="error_invalid_email">This phone number is invalid</string>
|
|
||||||
<string name="error_incorrect_pin">This pin or phone number is incorrect</string>
|
|
||||||
<string name="error_field_required">This field is required</string>
|
|
||||||
<string name="title_activity_rent">Rent Bike</string>
|
|
||||||
<string name="prompt_bike_id">Enter Bike UID</string>
|
|
||||||
<string name="action_rent_submit">Rent</string>
|
|
||||||
<string name="prompt_return_station_id">Enter the station UID where you leave the bike</string>
|
|
||||||
<string name="action_return_submit">Return</string>
|
|
||||||
<string name="title_activity_return">Return Bike</string>
|
|
||||||
<string name="action_map">Map</string>
|
|
||||||
<string name="indicator_no_bikes">No bikes here…</string>
|
|
||||||
<string name="indicator_electronic_lock">This is a bike with electric lock. Please just close the lock to return.</string>
|
|
||||||
|
|
||||||
<!-- machine readables -->
|
|
||||||
<string name="apikey">3IaBlP9OZw14dvES</string>
|
|
||||||
<string name="map_url"><![CDATA[https://nextbike.net/reservation/?lat=50.7086&lng=10.6348&zoom=5&maponly=1]]></string>
|
|
||||||
<string name="isLoggedIn">persistence</string>
|
|
||||||
<string name="action_open_with">Rent with NextCompanion</string>
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Base application theme. -->
|
|
||||||
<style name="AppTheme" parent="Theme.AppCompat">
|
|
||||||
<!-- Customize your theme here. -->
|
|
||||||
<item name="colorPrimary">@color/colorPrimary</item>
|
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
|
||||||
<item name="colorAccent">@color/colorAccent</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="AppTheme.NoActionBar">
|
|
||||||
<item name="windowActionBar">false</item>
|
|
||||||
<item name="windowNoTitle">true</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
|
||||||
|
|
||||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package com.example.hochi.nextcompanion;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
public class ExampleUnitTest {
|
|
||||||
@Test
|
|
||||||
public void addition_isCorrect() {
|
|
||||||
assertEquals(4, 2 + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
27
build.gradle
|
|
@ -1,27 +0,0 @@
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:3.3.1'
|
|
||||||
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
|
||||||
// in the individual module build.gradle files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task clean(type: Delete) {
|
|
||||||
delete rootProject.buildDir
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
# Project-wide Gradle settings.
|
|
||||||
# IDE (e.g. Android Studio) users:
|
|
||||||
# Gradle settings configured through the IDE *will override*
|
|
||||||
# any settings specified in this file.
|
|
||||||
# For more details on how to configure your build environment visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
|
||||||
org.gradle.jvmargs=-Xmx1536m
|
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
|
||||||
# org.gradle.parallel=true
|
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
|
|
@ -1,6 +0,0 @@
|
||||||
#Fri May 03 12:47:19 GMT 2019
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
|
|
||||||
172
gradlew
vendored
|
|
@ -1,172 +0,0 @@
|
||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
##
|
|
||||||
## Gradle start up script for UN*X
|
|
||||||
##
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >/dev/null
|
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
|
||||||
APP_BASE_NAME=`basename "$0"`
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS=""
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD="maximum"
|
|
||||||
|
|
||||||
warn () {
|
|
||||||
echo "$*"
|
|
||||||
}
|
|
||||||
|
|
||||||
die () {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
nonstop=false
|
|
||||||
case "`uname`" in
|
|
||||||
CYGWIN* )
|
|
||||||
cygwin=true
|
|
||||||
;;
|
|
||||||
Darwin* )
|
|
||||||
darwin=true
|
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
NONSTOP* )
|
|
||||||
nonstop=true
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
|
||||||
else
|
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD="java"
|
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
|
||||||
if [ $? -eq 0 ] ; then
|
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
ulimit -n $MAX_FD
|
|
||||||
if [ $? -ne 0 ] ; then
|
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
(0) set -- ;;
|
|
||||||
(1) set -- "$args0" ;;
|
|
||||||
(2) set -- "$args0" "$args1" ;;
|
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Escape application args
|
|
||||||
save () {
|
|
||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
|
||||||
echo " "
|
|
||||||
}
|
|
||||||
APP_ARGS=$(save "$@")
|
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
|
||||||
|
|
||||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
|
||||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
|
||||||
84
gradlew.bat
vendored
|
|
@ -1,84 +0,0 @@
|
||||||
@if "%DEBUG%" == "" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS=
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
|
||||||
echo.
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
echo location of your Java installation.
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windows variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
|
||||||
exit /b 1
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
include ':app'
|
|
||||||
115
src/main.rs
|
|
@ -243,7 +243,45 @@ fn build_ui(app: &Application) {
|
||||||
main_hdr.pack_end(&logout_btn);
|
main_hdr.pack_end(&logout_btn);
|
||||||
main_hdr.pack_start(&refresh_btn);
|
main_hdr.pack_start(&refresh_btn);
|
||||||
|
|
||||||
// ── Return sheet (bottom sheet) ───────────────────────────────────────────
|
// ── Bottom sheet (rent + return) ──────────────────────────────────────────
|
||||||
|
|
||||||
|
// — Rent form —
|
||||||
|
let bike_entry = Entry::builder()
|
||||||
|
.placeholder_text("Bike number")
|
||||||
|
.input_purpose(gtk::InputPurpose::Digits)
|
||||||
|
.build();
|
||||||
|
let rent_err = Label::builder()
|
||||||
|
.css_classes(["error"])
|
||||||
|
.wrap(true)
|
||||||
|
.visible(false)
|
||||||
|
.build();
|
||||||
|
let rent_submit = Button::builder()
|
||||||
|
.label("Rent")
|
||||||
|
.css_classes(["suggested-action", "pill"])
|
||||||
|
.build();
|
||||||
|
let rent_spinner = Spinner::new();
|
||||||
|
|
||||||
|
let rent_sheet = Box::builder()
|
||||||
|
.orientation(Orientation::Vertical)
|
||||||
|
.spacing(16)
|
||||||
|
.build();
|
||||||
|
let rent_sheet_title = Label::builder()
|
||||||
|
.css_classes(["title-4"])
|
||||||
|
.label("Rent Bike")
|
||||||
|
.xalign(0.0)
|
||||||
|
.build();
|
||||||
|
let rent_form = Box::builder()
|
||||||
|
.orientation(Orientation::Vertical)
|
||||||
|
.spacing(12)
|
||||||
|
.build();
|
||||||
|
rent_form.append(&bike_entry);
|
||||||
|
rent_form.append(&rent_err);
|
||||||
|
rent_form.append(&rent_submit);
|
||||||
|
rent_form.append(&rent_spinner);
|
||||||
|
rent_sheet.append(&rent_sheet_title);
|
||||||
|
rent_sheet.append(&rent_form);
|
||||||
|
|
||||||
|
// — Return form —
|
||||||
let station_entry = Entry::builder()
|
let station_entry = Entry::builder()
|
||||||
.placeholder_text("Station number")
|
.placeholder_text("Station number")
|
||||||
.input_purpose(gtk::InputPurpose::Digits)
|
.input_purpose(gtk::InputPurpose::Digits)
|
||||||
|
|
@ -278,21 +316,31 @@ fn build_ui(app: &Application) {
|
||||||
ret_inner.add_named(&manual_form, Some("manual"));
|
ret_inner.add_named(&manual_form, Some("manual"));
|
||||||
ret_inner.add_named(&electric_msg, Some("electric"));
|
ret_inner.add_named(&electric_msg, Some("electric"));
|
||||||
|
|
||||||
let sheet_title = Label::builder()
|
let ret_sheet = Box::builder()
|
||||||
|
.orientation(Orientation::Vertical)
|
||||||
|
.spacing(16)
|
||||||
|
.build();
|
||||||
|
let ret_sheet_title = Label::builder()
|
||||||
.css_classes(["title-4"])
|
.css_classes(["title-4"])
|
||||||
.label("Return Bike")
|
.label("Return Bike")
|
||||||
.xalign(0.0)
|
.xalign(0.0)
|
||||||
.build();
|
.build();
|
||||||
|
ret_sheet.append(&ret_sheet_title);
|
||||||
|
ret_sheet.append(&ret_inner);
|
||||||
|
|
||||||
|
// — Shared sheet stack —
|
||||||
|
let sheet_stack = Stack::new();
|
||||||
|
sheet_stack.add_named(&rent_sheet, Some("rent"));
|
||||||
|
sheet_stack.add_named(&ret_sheet, Some("return"));
|
||||||
|
|
||||||
let sheet_box = Box::builder()
|
let sheet_box = Box::builder()
|
||||||
.orientation(Orientation::Vertical)
|
.orientation(Orientation::Vertical)
|
||||||
.spacing(16)
|
|
||||||
.margin_top(8)
|
.margin_top(8)
|
||||||
.margin_bottom(24)
|
.margin_bottom(24)
|
||||||
.margin_start(16)
|
.margin_start(16)
|
||||||
.margin_end(16)
|
.margin_end(16)
|
||||||
.build();
|
.build();
|
||||||
sheet_box.append(&sheet_title);
|
sheet_box.append(&sheet_stack);
|
||||||
sheet_box.append(&ret_inner);
|
|
||||||
|
|
||||||
let bottom_sheet = BottomSheet::builder()
|
let bottom_sheet = BottomSheet::builder()
|
||||||
.show_drag_handle(true)
|
.show_drag_handle(true)
|
||||||
|
|
@ -313,44 +361,6 @@ fn build_ui(app: &Application) {
|
||||||
.child(&main_body)
|
.child(&main_body)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// ── Rent page ─────────────────────────────────────────────────────────────
|
|
||||||
let bike_entry = Entry::builder()
|
|
||||||
.placeholder_text("Bike number")
|
|
||||||
.input_purpose(gtk::InputPurpose::Digits)
|
|
||||||
.build();
|
|
||||||
let rent_err = Label::builder()
|
|
||||||
.css_classes(["error"])
|
|
||||||
.wrap(true)
|
|
||||||
.visible(false)
|
|
||||||
.build();
|
|
||||||
let rent_submit = Button::builder()
|
|
||||||
.label("Rent")
|
|
||||||
.css_classes(["suggested-action", "pill"])
|
|
||||||
.build();
|
|
||||||
let rent_spinner = Spinner::new();
|
|
||||||
|
|
||||||
let rent_form = Box::builder()
|
|
||||||
.orientation(Orientation::Vertical)
|
|
||||||
.spacing(12)
|
|
||||||
.margin_top(24).margin_bottom(24).margin_start(12).margin_end(12)
|
|
||||||
.build();
|
|
||||||
rent_form.append(&bike_entry);
|
|
||||||
rent_form.append(&rent_err);
|
|
||||||
rent_form.append(&rent_submit);
|
|
||||||
rent_form.append(&rent_spinner);
|
|
||||||
|
|
||||||
let rent_clamp = Clamp::builder().maximum_size(400).build();
|
|
||||||
rent_clamp.set_child(Some(&rent_form));
|
|
||||||
|
|
||||||
let rent_body = Box::builder().orientation(Orientation::Vertical).build();
|
|
||||||
rent_body.append(&HeaderBar::new());
|
|
||||||
rent_body.append(&rent_clamp);
|
|
||||||
|
|
||||||
let rent_page = NavigationPage::builder()
|
|
||||||
.title("Rent Bike")
|
|
||||||
.child(&rent_body)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
// ── Navigation view ───────────────────────────────────────────────────────
|
// ── Navigation view ───────────────────────────────────────────────────────
|
||||||
let nav = NavigationView::new();
|
let nav = NavigationView::new();
|
||||||
nav.push(&main_page);
|
nav.push(&main_page);
|
||||||
|
|
@ -452,14 +462,17 @@ fn build_ui(app: &Application) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Open rent page ────────────────────────────────────────────────────────
|
// ── Open rent sheet ───────────────────────────────────────────────────────
|
||||||
{
|
{
|
||||||
let nav = nav.clone();
|
let bottom_sheet = bottom_sheet.clone();
|
||||||
let rent_page = rent_page.clone();
|
let sheet_stack = sheet_stack.clone();
|
||||||
let bike_entry = bike_entry.clone();
|
let bike_entry = bike_entry.clone();
|
||||||
|
let rent_err = rent_err.clone();
|
||||||
rent_btn.connect_clicked(move |_| {
|
rent_btn.connect_clicked(move |_| {
|
||||||
bike_entry.set_text("");
|
bike_entry.set_text("");
|
||||||
nav.push(&rent_page);
|
rent_err.set_visible(false);
|
||||||
|
sheet_stack.set_visible_child_name("rent");
|
||||||
|
bottom_sheet.set_open(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -470,7 +483,7 @@ fn build_ui(app: &Application) {
|
||||||
let err = rent_err.clone();
|
let err = rent_err.clone();
|
||||||
let spinner = rent_spinner.clone();
|
let spinner = rent_spinner.clone();
|
||||||
let btn = rent_submit.clone();
|
let btn = rent_submit.clone();
|
||||||
let nav = nav.clone();
|
let bottom_sheet = bottom_sheet.clone();
|
||||||
let bikes = bikes.clone();
|
let bikes = bikes.clone();
|
||||||
let bikes_list = bikes_list.clone();
|
let bikes_list = bikes_list.clone();
|
||||||
let list_stack = list_stack.clone();
|
let list_stack = list_stack.clone();
|
||||||
|
|
@ -489,7 +502,7 @@ fn build_ui(app: &Application) {
|
||||||
let spinner = spinner.clone();
|
let spinner = spinner.clone();
|
||||||
let btn = btn.clone();
|
let btn = btn.clone();
|
||||||
let err = err.clone();
|
let err = err.clone();
|
||||||
let nav = nav.clone();
|
let bottom_sheet = bottom_sheet.clone();
|
||||||
let bikes = bikes.clone();
|
let bikes = bikes.clone();
|
||||||
let bikes_list = bikes_list.clone();
|
let bikes_list = bikes_list.clone();
|
||||||
let list_stack = list_stack.clone();
|
let list_stack = list_stack.clone();
|
||||||
|
|
@ -505,7 +518,7 @@ fn build_ui(app: &Application) {
|
||||||
err.set_label(&e);
|
err.set_label(&e);
|
||||||
err.set_visible(true);
|
err.set_visible(true);
|
||||||
} else {
|
} else {
|
||||||
nav.pop();
|
bottom_sheet.set_open(false);
|
||||||
load_rentals(key_reload, bikes, bikes_list, list_stack).await;
|
load_rentals(key_reload, bikes, bikes_list, list_stack).await;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -516,6 +529,7 @@ fn build_ui(app: &Application) {
|
||||||
// ── Click rental row → open return bottom sheet ───────────────────────────
|
// ── Click rental row → open return bottom sheet ───────────────────────────
|
||||||
{
|
{
|
||||||
let bottom_sheet = bottom_sheet.clone();
|
let bottom_sheet = bottom_sheet.clone();
|
||||||
|
let sheet_stack = sheet_stack.clone();
|
||||||
let bikes = bikes.clone();
|
let bikes = bikes.clone();
|
||||||
let return_bike = return_bike.clone();
|
let return_bike = return_bike.clone();
|
||||||
let ret_inner = ret_inner.clone();
|
let ret_inner = ret_inner.clone();
|
||||||
|
|
@ -529,6 +543,7 @@ fn build_ui(app: &Application) {
|
||||||
ret_err.set_visible(false);
|
ret_err.set_visible(false);
|
||||||
ret_inner.set_visible_child_name(if bike.electric_lock { "electric" } else { "manual" });
|
ret_inner.set_visible_child_name(if bike.electric_lock { "electric" } else { "manual" });
|
||||||
*return_bike.borrow_mut() = Some(bike);
|
*return_bike.borrow_mut() = Some(bike);
|
||||||
|
sheet_stack.set_visible_child_name("return");
|
||||||
bottom_sheet.set_open(true);
|
bottom_sheet.set_open(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||