parent
13f42723a0
commit
c1791a22be
38 changed files with 13 additions and 879 deletions
|
@ -1,5 +1,6 @@
|
|||
1.5.9:
|
||||
- Resolve possible crash when waking device
|
||||
- Remove usage of Google Play Services (was previously used in releases on Google Play and Amazon)
|
||||
|
||||
1.5.8:
|
||||
- Resolve minor sound delay by preloading sounds
|
||||
|
|
|
@ -2,14 +2,14 @@ apply plugin: 'com.android.application'
|
|||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '29.0.2'
|
||||
buildToolsVersion '29.0.3'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
|
||||
versionCode 158
|
||||
versionName "1.5.8"
|
||||
versionCode 159
|
||||
versionName "1.5.9"
|
||||
|
||||
applicationId "sh.ftp.rocketninelabs.meditationassistant"
|
||||
manifestPlaceholders = [
|
||||
|
@ -75,32 +75,18 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'androidx.core:core:1.1.0'
|
||||
implementation 'androidx.core:core:1.2.0'
|
||||
implementation 'androidx.legacy:legacy-support-core-utils:1.0.0'
|
||||
implementation 'androidx.legacy:legacy-support-core-ui:1.0.0'
|
||||
implementation 'androidx.media:media:1.1.0'
|
||||
implementation 'androidx.fragment:fragment:1.1.0'
|
||||
implementation 'androidx.fragment:fragment:1.2.2'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
implementation "net.openid:appauth:0.7.1"
|
||||
implementation "com.squareup.okio:okio:2.2.2"
|
||||
implementation 'com.opencsv:opencsv:4.6'
|
||||
implementation "net.margaritov.preference.colorpicker.ColorPickerPreference:ColorPickerPreference:1.0.0"
|
||||
|
||||
freeImplementation 'com.google.android.gms:play-services-base:16.1.0'
|
||||
fullImplementation 'com.google.android.gms:play-services-base:16.1.0'
|
||||
freeImplementation 'com.google.android.gms:play-services-analytics:16.0.8'
|
||||
fullImplementation 'com.google.android.gms:play-services-analytics:16.0.8'
|
||||
//freeImplementation 'com.google.android.gms:play-services-wearable:15.0.1'
|
||||
//fullImplementation 'com.google.android.gms:play-services-wearable:15.0.1'
|
||||
freeImplementation 'com.google.android.gms:play-services-appinvite:16.1.1'
|
||||
fullImplementation 'com.google.android.gms:play-services-appinvite:16.1.1'
|
||||
freeImplementation 'com.google.android.gms:play-services-fitness:16.0.1'
|
||||
fullImplementation 'com.google.android.gms:play-services-fitness:16.0.1'
|
||||
//noinspection GradleDynamicVersion
|
||||
implementation 'com.google.android.material:material:1.1.0'
|
||||
implementation 'ch.acra:acra-http:5.3.0'
|
||||
implementation 'com.github.amlcurran.showcaseview:library:5.4.3'
|
||||
implementation "net.openid:appauth:0.7.1"
|
||||
implementation 'com.opencsv:opencsv:4.6'
|
||||
implementation "com.squareup.okio:okio:2.2.2"
|
||||
implementation 'com.nononsenseapps:filepicker:4.2.1'
|
||||
//wearApp project(':MeditationAssistantWear')
|
||||
// TODO: Uncomment when Wear app is ready
|
||||
implementation 'com.github.amlcurran.showcaseview:library:5.4.3'
|
||||
implementation "net.margaritov.preference.colorpicker.ColorPickerPreference:ColorPickerPreference:1.0.0"
|
||||
}
|
||||
|
|
|
@ -1,46 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="sh.ftp.rocketninelabs.meditationassistant">
|
||||
|
||||
<application>
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.analytics.globalConfigResource"
|
||||
android:resource="@xml/analytics" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.ads.APPLICATION_ID"
|
||||
android:value="ca-app-pub-6158454562572132~3051388356" />
|
||||
<meta-data
|
||||
android:name="com.google.android.backup.api_key"
|
||||
android:value="AEdPqrEAAAAIqq_HCa56eFzfQpNSwYUIIytAyO6bh4fFUFUcYA" />
|
||||
|
||||
<receiver
|
||||
android:name="com.google.android.gms.analytics.AnalyticsReceiver"
|
||||
android:enabled="true"
|
||||
tools:ignore="ExportedReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.analytics.ANALYTICS_DISPATCH" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<!-- Register Wear data layer service
|
||||
<service android:name=".WearListenerService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.BIND_LISTENER"/>
|
||||
</intent-filter>
|
||||
</service> -->
|
||||
|
||||
<!-- Activities -->
|
||||
<service
|
||||
android:name="com.google.android.gms.analytics.AnalyticsService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -1,42 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="sh.ftp.rocketninelabs.meditationassistant">
|
||||
|
||||
<application>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.backup.api_key"
|
||||
android:value="AEdPqrEAAAAImiscQeePK7-fr6JMj14zZX47kvR0lSKdCgjnXQ" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.analytics.globalConfigResource"
|
||||
android:resource="@xml/analytics" />
|
||||
|
||||
<receiver
|
||||
android:name="com.google.android.gms.analytics.AnalyticsReceiver"
|
||||
android:enabled="true"
|
||||
tools:ignore="ExportedReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.analytics.ANALYTICS_DISPATCH" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<service
|
||||
android:name="com.google.android.gms.analytics.AnalyticsService"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
<!-- Register Wear data layer service
|
||||
<service android:name=".WearListenerService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.BIND_LISTENER"/>
|
||||
</intent-filter>
|
||||
</service> -->
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -63,8 +63,6 @@ public class AboutActivity extends Activity {
|
|||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
getMeditationAssistant().utility.initializeTracker(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,12 +89,7 @@ public class AboutActivity extends Activity {
|
|||
NavUtils.navigateUpFromSameTask(this);
|
||||
return true;
|
||||
} else if (i == R.id.action_share_app) {
|
||||
try {
|
||||
Intent intent = getMeditationAssistant().utility.getAppShareIntent();
|
||||
startActivityForResult(intent, 1337);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// TODO Reimplement as standard share
|
||||
} else if (i == R.id.action_rate) {
|
||||
getMeditationAssistant().rateApp();
|
||||
return true;
|
||||
|
@ -105,18 +98,6 @@ public class AboutActivity extends Activity {
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getMeditationAssistant().utility.trackingStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
getMeditationAssistant().utility.trackingStop(this);
|
||||
}
|
||||
|
||||
public void learnMore(View view) {
|
||||
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(MeditationAssistant.URL_SOURCE)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
}
|
||||
|
|
|
@ -155,8 +155,6 @@ public class CompleteActivity extends Activity {
|
|||
getMeditationAssistant().restoreVolume();
|
||||
}
|
||||
|
||||
getMeditationAssistant().utility.initializeTracker(this);
|
||||
|
||||
if (!manual) {
|
||||
getMeditationAssistant().vibrateDevice();
|
||||
|
||||
|
@ -238,33 +236,6 @@ public class CompleteActivity extends Activity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getMeditationAssistant().utility.trackingStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
getMeditationAssistant().utility.trackingStop(this);
|
||||
}
|
||||
|
||||
public void postMediNET(View view) {
|
||||
if (getMeditationAssistant().getMediNETKey().equals("")) {
|
||||
getMeditationAssistant().startAuth(CompleteActivity.this, true);
|
||||
|
|
|
@ -170,8 +170,6 @@ public class MainActivity extends Activity implements OnShowcaseEventListener {
|
|||
setTheme(getMeditationAssistant().getMATheme());
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
getMeditationAssistant().utility.initializeTracker(this);
|
||||
|
||||
handler = new Handler();
|
||||
|
||||
am = getMeditationAssistant().getAlarmManager();
|
||||
|
@ -1651,23 +1649,6 @@ public class MainActivity extends Activity implements OnShowcaseEventListener {
|
|||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
getMeditationAssistant().utility.trackingStart(this);
|
||||
getMeditationAssistant().utility.connectGoogleClient();
|
||||
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getMeditationAssistant().utility.trackingStop(this);
|
||||
|
||||
getMeditationAssistant().utility.disconnectGoogleClient();
|
||||
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (!getMeditationAssistant().getPrefs().getBoolean("pref_autosignin", false) && !getMeditationAssistant().getPrefs().getString("key", "").equals("")) {
|
||||
|
@ -2102,16 +2083,6 @@ public class MainActivity extends Activity implements OnShowcaseEventListener {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
if (requestCode == MeditationAssistant.REQUEST_FIT) {
|
||||
getMeditationAssistant().utility.googleAPIAuthInProgress = false;
|
||||
if (resultCode == RESULT_OK) {
|
||||
getMeditationAssistant().utility.onGoogleClientResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void pressCommunity(View view) {
|
||||
if (sv != null && sv.isShown()) {
|
||||
try {
|
||||
|
|
|
@ -281,8 +281,6 @@ public class MediNETActivity extends Activity {
|
|||
setContentView(R.layout.activity_medinet);
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
getMeditationAssistant().utility.initializeTracker(this);
|
||||
|
||||
initUI(true);
|
||||
}
|
||||
|
||||
|
@ -394,18 +392,6 @@ public class MediNETActivity extends Activity {
|
|||
webView.saveState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getMeditationAssistant().utility.trackingStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
getMeditationAssistant().utility.trackingStop(this);
|
||||
}
|
||||
|
||||
public void setWindowBackground() {
|
||||
if (getMeditationAssistant().getMATheme() != R.style.MeditationDarkTheme && getMeditationAssistant().getMATheme() != R.style.Buddhism) {
|
||||
getWindow().setBackgroundDrawable(
|
||||
|
|
|
@ -110,7 +110,6 @@ public class MeditationAssistant extends Application {
|
|||
public PendingIntent reminderPendingIntent = null;
|
||||
public String theme = null;
|
||||
public String marketName = null;
|
||||
public UtilityMA utility = new UtilityMA();
|
||||
public Integer previous_volume = null;
|
||||
private String appVersion = null;
|
||||
private long timeToStopMeditate = 0;
|
||||
|
@ -1125,8 +1124,6 @@ public class MeditationAssistant extends Application {
|
|||
super.onCreate();
|
||||
ACRA.init(this);
|
||||
|
||||
utility.ma = this;
|
||||
|
||||
CookieManager cookieManager = new CookieManager();
|
||||
CookieHandler.setDefault(cookieManager);
|
||||
|
||||
|
@ -1204,13 +1201,6 @@ public class MeditationAssistant extends Application {
|
|||
return result.toString();
|
||||
}
|
||||
|
||||
public boolean sendUsageReports() {
|
||||
if (sendusage == null) {
|
||||
sendusage = getPrefs().getBoolean("pref_sendusage", true);
|
||||
}
|
||||
return sendusage;
|
||||
}
|
||||
|
||||
public void setMediNETKey(String key, String provider) {
|
||||
Log.d("MeditationAssistant", "Setting medinet key: " + key + " - " + provider);
|
||||
medinetkey = key;
|
||||
|
|
|
@ -85,8 +85,6 @@ public class ProgressActivity extends FragmentActivity {
|
|||
} else {
|
||||
mViewPager.setCurrentItem(CALENDAR_FRAGMENT, false);
|
||||
}
|
||||
|
||||
getMeditationAssistant().utility.initializeTracker(this);
|
||||
}
|
||||
|
||||
public void goToSessionAtDate(int[] date) {
|
||||
|
@ -242,18 +240,6 @@ public class ProgressActivity extends FragmentActivity {
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getMeditationAssistant().utility.trackingStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
getMeditationAssistant().utility.trackingStop(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
|
|
@ -449,22 +449,9 @@ public class SettingsActivity extends PreferenceActivity {
|
|||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
setTheme(getMeditationAssistant().getMATheme());
|
||||
getMeditationAssistant().utility.initializeTracker(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
getMeditationAssistant().utility.trackingStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
getMeditationAssistant().utility.trackingStop(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
|
@ -716,11 +703,6 @@ public class SettingsActivity extends PreferenceActivity {
|
|||
bindPreferenceSummaryToValue(preferenceFragment == null ? findPreference("pref_theme") : preferenceFragment.findPreference("pref_theme"));
|
||||
bindPreferenceSummaryToValue(preferenceFragment == null ? findPreference("pref_widgetcolor") : preferenceFragment.findPreference("pref_widgetcolor"));
|
||||
bindPreferenceSummaryToValue(preferenceFragment == null ? findPreference("pref_mainbuttons") : preferenceFragment.findPreference("pref_mainbuttons"));
|
||||
|
||||
if (BuildConfig.FLAVOR.equals("opensource")) { // Hide usage statistics preference, as tracking is completely disabled
|
||||
CheckBoxPreference pref_sendusage = (CheckBoxPreference) (preferenceFragment == null ? findPreference("pref_sendusage") : preferenceFragment.findPreference("pref_sendusage"));
|
||||
(preferenceFragment == null ? getPreferenceScreen() : preferenceFragment.getPreferenceScreen()).removePreference(pref_sendusage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,10 +22,4 @@
|
|||
android:key="pref_widgetcolor"
|
||||
android:title="@string/pref_widgetcolor" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:defaultValue="true"
|
||||
android:key="pref_sendusage"
|
||||
android:summary="@string/pref_sendusage_summary"
|
||||
android:title="@string/pref_sendusage" />
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -3,11 +3,9 @@
|
|||
package="sh.ftp.rocketninelabs.meditationassistant">
|
||||
|
||||
<application>
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.backup.api_key"
|
||||
android:value="AEdPqrEAAAAIAUEb3SC2bBJt6pLanNwm7yB1Qy2WFS_nm7pHuw" />
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
|
||||
public class UtilityMA {
|
||||
|
||||
public MeditationAssistant ma = null;
|
||||
public boolean googleAPIAuthInProgress = false;
|
||||
|
||||
public void initializeTracker(Activity activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void setupGoogleClient(final Activity activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void sendFitData() {
|
||||
return;
|
||||
}
|
||||
|
||||
public void loadAd(Activity activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void pauseAd(Activity activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void resumeAd(Activity activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void destroyAd(Activity activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void trackingStart(Activity activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void trackingStop(Activity activity) {
|
||||
return;
|
||||
}
|
||||
|
||||
public void connectGoogleClient() {
|
||||
return;
|
||||
}
|
||||
|
||||
public void disconnectGoogleClient() {
|
||||
return;
|
||||
}
|
||||
|
||||
public void onGoogleClientResult() {
|
||||
return;
|
||||
}
|
||||
|
||||
public Intent getAppShareIntent() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,195 +0,0 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.analytics.GoogleAnalytics;
|
||||
import com.google.android.gms.analytics.Tracker;
|
||||
import com.google.android.gms.appinvite.AppInviteInvitation;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.GooglePlayServicesUtil;
|
||||
import com.google.android.gms.common.Scopes;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.Scope;
|
||||
import com.google.android.gms.fitness.Fitness;
|
||||
import com.google.android.gms.fitness.FitnessActivities;
|
||||
import com.google.android.gms.fitness.data.Session;
|
||||
import com.google.android.gms.fitness.request.SessionInsertRequest;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class UtilityMA {
|
||||
public MeditationAssistant ma = null;
|
||||
public GoogleApiClient googleClient = null;
|
||||
public HashMap<MeditationAssistant.TrackerName, Tracker> mTrackers = new HashMap<>();
|
||||
public boolean googleAPIAuthInProgress = false;
|
||||
|
||||
private MeditationAssistant getMeditationAssistant() {
|
||||
return ma;
|
||||
}
|
||||
|
||||
synchronized public Tracker getTracker(Activity activity, MeditationAssistant.TrackerName trackerId) {
|
||||
if (!mTrackers.containsKey(trackerId)) {
|
||||
GoogleAnalytics analytics = GoogleAnalytics.getInstance(activity);
|
||||
Tracker t = analytics.newTracker(R.xml.analytics_tracker);
|
||||
t.set("Market", getMeditationAssistant().getMarketName());
|
||||
mTrackers.put(trackerId, t);
|
||||
}
|
||||
return mTrackers.get(trackerId);
|
||||
}
|
||||
|
||||
public void initializeTracker(Activity activity) {
|
||||
if (getMeditationAssistant().sendUsageReports()) {
|
||||
getTracker(activity, MeditationAssistant.TrackerName.APP_TRACKER);
|
||||
}
|
||||
}
|
||||
|
||||
public void setupGoogleClient(final Activity activity) {
|
||||
//if (googleClient != null) {
|
||||
/// return;
|
||||
//}
|
||||
Log.d("MeditationAssistant", "Setting up Google Fit");
|
||||
|
||||
googleClient = new GoogleApiClient.Builder(activity)
|
||||
.addApi(Fitness.HISTORY_API)
|
||||
.addScope(new Scope(Scopes.FITNESS_ACTIVITY_READ_WRITE))
|
||||
.addConnectionCallbacks(
|
||||
new GoogleApiClient.ConnectionCallbacks() {
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle bundle) {
|
||||
Log.d("MeditationAssistant", "!!! Connected to Google Fit");
|
||||
// Now you can make calls to the Fitness APIs.
|
||||
// Put application specific code here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int i) {
|
||||
// If your connection to the sensor gets lost at some point,
|
||||
// you'll be able to determine the reason and react to it here.
|
||||
if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
|
||||
Log.d("MeditationAssistant", "Connection lost. Cause: Network Lost.");
|
||||
} else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
|
||||
Log.d("MeditationAssistant", "Connection lost. Reason: Service Disconnected");
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.addOnConnectionFailedListener(
|
||||
new GoogleApiClient.OnConnectionFailedListener() {
|
||||
// Called whenever the API client fails to connect.
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult result) {
|
||||
Log.d("MeditationAssistant", "Connection failed. Cause: " + result.toString());
|
||||
if (!result.hasResolution()) {
|
||||
// Show the localized error dialog
|
||||
GooglePlayServicesUtil.getErrorDialog(result.getErrorCode(),
|
||||
activity, 0).show();
|
||||
return;
|
||||
}
|
||||
// The failure has a resolution. Resolve it.
|
||||
// Called typically when the app is not yet authorized, and an
|
||||
// authorization dialog is displayed to the user.
|
||||
if (!googleAPIAuthInProgress) {
|
||||
try {
|
||||
Log.d("MeditationAssistant", "Attempting to resolve failed connection");
|
||||
googleAPIAuthInProgress = true;
|
||||
result.startResolutionForResult(activity,
|
||||
MeditationAssistant.REQUEST_FIT);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
Log.d("MeditationAssistant",
|
||||
"Exception while starting resolution activity", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.build();
|
||||
}
|
||||
|
||||
public void sendFitData() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
Date now = new Date();
|
||||
cal.setTime(now);
|
||||
long endTime = cal.getTimeInMillis();
|
||||
cal.add(Calendar.HOUR, -1);
|
||||
long startTime = cal.getTimeInMillis();
|
||||
|
||||
Session session = new Session.Builder()
|
||||
.setName("No name")
|
||||
.setDescription("Duration: blah blah")
|
||||
.setIdentifier("meditation" + "11231241")
|
||||
.setActivity(FitnessActivities.MEDITATION)
|
||||
.setStartTime(startTime, TimeUnit.MILLISECONDS)
|
||||
.setEndTime(endTime, TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
|
||||
SessionInsertRequest insertRequest = new SessionInsertRequest.Builder()
|
||||
.setSession(session)
|
||||
.build();
|
||||
|
||||
// Then, invoke the Sessions API to insert the session and await the result,
|
||||
// which is possible here because of the AsyncTask. Always include a timeout when
|
||||
// calling await() to avoid hanging that can occur from the service being shutdown
|
||||
// because of low memory or other conditions.
|
||||
Log.d("MeditationAssistant", "Inserting the session in the History API");
|
||||
com.google.android.gms.common.api.Status insertStatus =
|
||||
Fitness.SessionsApi.insertSession(googleClient, insertRequest)
|
||||
.await(1, TimeUnit.MINUTES);
|
||||
|
||||
// Before querying the session, check to see if the insertion succeeded.
|
||||
if (!insertStatus.isSuccess()) {
|
||||
Log.d("MeditationAssistant", "There was a problem inserting the session: " +
|
||||
insertStatus.getStatusMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point, the session has been inserted and can be read.
|
||||
Log.i("MeditationAssistant", "Session insert was successful!");
|
||||
}
|
||||
|
||||
public void trackingStart(Activity activity) {
|
||||
if (getMeditationAssistant().sendUsageReports()) {
|
||||
GoogleAnalytics.getInstance(activity).reportActivityStart(activity);
|
||||
}
|
||||
}
|
||||
|
||||
public void trackingStop(Activity activity) {
|
||||
if (getMeditationAssistant().sendUsageReports()) {
|
||||
GoogleAnalytics.getInstance(activity).reportActivityStop(activity);
|
||||
}
|
||||
}
|
||||
|
||||
public void connectGoogleClient() {
|
||||
if (googleClient != null) {
|
||||
googleClient.connect();
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnectGoogleClient() {
|
||||
if (googleClient != null && googleClient.isConnected()) {
|
||||
googleClient.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public void onGoogleClientResult() {
|
||||
// Make sure the app is not already connected or attempting to connect
|
||||
if (!googleClient.isConnecting() && !googleClient.isConnected()) {
|
||||
connectGoogleClient();
|
||||
|
||||
sendFitData();
|
||||
}
|
||||
}
|
||||
|
||||
public Intent getAppShareIntent() {
|
||||
return new AppInviteInvitation.IntentBuilder(getMeditationAssistant().getString(R.string.appNameShort))
|
||||
.setMessage(getMeditationAssistant().getString(R.string.invitationBlurb))
|
||||
.build();
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
/*
|
||||
import android.util.Log;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.data.FreezableUtils;
|
||||
import com.google.android.gms.wearable.DataEventBuffer;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.wearable.WearableListenerService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class WearListenerService extends WearableListenerService {
|
||||
|
||||
private static final String TAG = "MeditationAssistant";
|
||||
private static final String START_ACTIVITY_PATH = "/start-activity";
|
||||
private static final String DATA_ITEM_RECEIVED_PATH = "/data-item-received";
|
||||
|
||||
@Override
|
||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "onDataChanged: " + dataEvents);
|
||||
}
|
||||
final List events = FreezableUtils
|
||||
.freezeIterable(dataEvents);
|
||||
|
||||
GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.build();
|
||||
|
||||
ConnectionResult connectionResult =
|
||||
googleApiClient.blockingConnect(30, TimeUnit.SECONDS);
|
||||
|
||||
if (!connectionResult.isSuccess()) {
|
||||
Log.e(TAG, "Failed to connect to GoogleApiClient.");
|
||||
}
|
||||
|
||||
// Loop through the events and send a message
|
||||
// to the node that created the data item.
|
||||
/*for (DataEvent event : events) {
|
||||
Uri uri = event.getDataItem().getUri();
|
||||
|
||||
// Get the node id from the host value of the URI
|
||||
String nodeId = uri.getHost();
|
||||
// Set the data of the message to be the bytes of the URI
|
||||
byte[] payload = uri.toString().getBytes();
|
||||
|
||||
// Send the RPC
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, nodeId,
|
||||
DATA_ITEM_RECEIVED_PATH, payload);
|
||||
}
|
||||
}
|
||||
}*/
|
1
MeditationAssistantWear/.gitignore
vendored
1
MeditationAssistantWear/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
/build
|
|
@ -1,35 +0,0 @@
|
|||
/*buildscript {
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '26.0.1'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 20
|
||||
targetSdkVersion 26
|
||||
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false /* Docs say to not compress wear APK *//*
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.google.android.gms:play-services-wearable:11.0.4'
|
||||
}*/
|
|
@ -1,4 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<ignore path="build/**"/>
|
||||
</lint>
|
17
MeditationAssistantWear/proguard-rules.pro
vendored
17
MeditationAssistantWear/proguard-rules.pro
vendored
|
@ -1,17 +0,0 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /home/trevor/programming/android-sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# 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 *;
|
||||
#}
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
package="sh.ftp.rocketninelabs.meditationassistant"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-feature android:name="android.hardware.type.watch"/>
|
||||
|
||||
<application
|
||||
android:name=".WearMeditationAssistant"
|
||||
android:allowBackup="true"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.DeviceDefault">
|
||||
<activity
|
||||
android:name=".WearMainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".WearEditDurationActivity"
|
||||
android:label=""
|
||||
android:launchMode="singleTask"
|
||||
android:noHistory="true"
|
||||
android:parentActivityName=".WearMainActivity"
|
||||
android:theme="@style/NoSwipe"></activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -1,40 +0,0 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.support.wearable.view.WatchViewStub;
|
||||
import android.view.View;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
public class WearEditDurationActivity extends Activity {
|
||||
|
||||
private TimePicker editDuration = null;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final WearMeditationAssistant wma = (WearMeditationAssistant) getApplication();
|
||||
|
||||
setContentView(R.layout.wear_editduration);
|
||||
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
|
||||
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
|
||||
@Override
|
||||
public void onLayoutInflated(WatchViewStub stub) {
|
||||
editDuration = (TimePicker) stub.findViewById(R.id.editWearDuration);
|
||||
editDuration.setIs24HourView(true);
|
||||
|
||||
editDuration.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
|
||||
@Override
|
||||
public void onTimeChanged(TimePicker timePicker, int i, int i1) {
|
||||
wma.newDuration = String.valueOf(editDuration.getCurrentHour()) + ":" + String.valueOf(editDuration.getCurrentMinute());
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setDuration(View v) {
|
||||
finish();
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.wearable.view.WatchViewStub;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
|
||||
public class WearMainActivity extends Activity implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
private TextView wearTimer;
|
||||
private GoogleApiClient mGoogleApiClient;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.wear_main);
|
||||
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
|
||||
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
|
||||
@Override
|
||||
public void onLayoutInflated(WatchViewStub stub) {
|
||||
wearTimer = (TextView) stub.findViewById(R.id.wearTimer);
|
||||
|
||||
wearTimer.setText("0:15");
|
||||
wearTimer.setTextSize(33 * getResources().getDisplayMetrics().scaledDensity);
|
||||
|
||||
wearTimer.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Intent intent = new Intent(WearMainActivity.this, WearEditDurationActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivityForResult(intent, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
mGoogleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.addConnectionCallbacks(this)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
Log.d("MeditationAssistant", "WEAR - Connection status: " + String.valueOf(mGoogleApiClient.isConnected()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
WearMeditationAssistant wma = (WearMeditationAssistant) getApplication();
|
||||
|
||||
if (wma.newDuration != "") {
|
||||
wearTimer.setText(wma.newDuration);
|
||||
wma.newDuration = "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle bundle) {
|
||||
Log.d("MeditationAssistant", "WEAR - Connected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int i) {
|
||||
Log.d("MeditationAssistant", "WEAR - Suspended");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||
Log.d("MeditationAssistant", "WEAR - Failed");
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package sh.ftp.rocketninelabs.meditationassistant;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
public class WearMeditationAssistant extends Application {
|
||||
public String newDuration = "";
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.wearable.view.WatchViewStub
|
||||
android:id="@+id/watch_view_stub"
|
||||
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:rectLayout="@layout/wear_editduration_rect"
|
||||
app:roundLayout="@layout/wear_editduration_round"
|
||||
tools:context=".WearEditDurationActivity"
|
||||
tools:deviceIds="wear"></android.support.wearable.view.WatchViewStub>
|
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout 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:orientation="vertical"
|
||||
tools:context=".WearEditDurationActivity"
|
||||
tools:deviceIds="wear_square">
|
||||
|
||||
<TimePicker
|
||||
android:id="@+id/editWearDuration"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="40dp"
|
||||
android:layout_marginTop="-20dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/setDuration"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:onClick="setDuration"
|
||||
android:text="@string/set"></Button>
|
||||
</RelativeLayout>
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
android:id="@+id/wear_editduration_layout"
|
||||
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"
|
||||
tools:context=".WearEditDurationActivity"
|
||||
tools:deviceIds="wear_round">
|
||||
|
||||
<TimePicker
|
||||
android:id="@+id/editWearDuration"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="40dp"
|
||||
android:layout_marginTop="-20dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/setDuration"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="60dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:onClick="setDuration"
|
||||
android:text="@string/set"></Button>
|
||||
</RelativeLayout>
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.wearable.view.WatchViewStub
|
||||
android:id="@+id/watch_view_stub"
|
||||
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:rectLayout="@layout/wear_main_rect"
|
||||
app:roundLayout="@layout/wear_main_round"
|
||||
tools:context=".WearMainActivity"
|
||||
tools:deviceIds="wear"></android.support.wearable.view.WatchViewStub>
|
|
@ -1,16 +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:orientation="vertical"
|
||||
tools:context=".MainActivity"
|
||||
tools:deviceIds="wear_square">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/wearTimer"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
</LinearLayout>
|
|
@ -1,16 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout 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"
|
||||
tools:context=".MainActivity"
|
||||
tools:deviceIds="wear_round">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/wearTimer"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
</RelativeLayout>
|
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
|
@ -1,5 +0,0 @@
|
|||
<resources>
|
||||
<string name="app_name">Meditation Assistant</string>
|
||||
|
||||
<string name="set">Set</string>
|
||||
</resources>
|
|
@ -1,15 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="Theme.Dialog.WearDialog" parent="@android:style/Theme.Dialog">
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<!--item name="android:windowTitleStyle">@android:style/DialogWindowTitle</item-->
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="NoSwipe" parent="@android:style/Theme.DeviceDefault">
|
||||
<item name="android:windowSwipeToDismiss">false</item>
|
||||
</style>
|
||||
</resources>
|
|
@ -1,3 +1 @@
|
|||
include ':MeditationAssistant'
|
||||
// TODO: Add when wear app is ready
|
||||
// , ':MeditationAssistantWear'
|
||||
|
|
Loading…
Reference in a new issue