|
@ -20,8 +20,8 @@
|
|||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.owncloud.android"
|
||||
android:versionCode="10040002"
|
||||
android:versionName="1.4.0 RC2">
|
||||
android:versionCode="10040003"
|
||||
android:versionName="1.4.0 RC3">
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
|
@ -183,7 +183,7 @@
|
|||
android:name=".authentication.AuthenticatorActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/Theme.ownCloud.noActionBar.Login" >
|
||||
android:theme="@style/Theme.ownCloud.noActionBar.Login">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
|
@ -219,7 +219,9 @@
|
|||
|
||||
<activity android:name=".ui.errorhandling.ErrorShowActivity" />
|
||||
<activity android:name=".ui.activity.UploadListActivity" />
|
||||
|
||||
<activity android:name=".ui.activity.WhatsNewActivity"
|
||||
android:theme="@style/Theme.ownCloud.noActionBar.Login" />
|
||||
|
||||
<receiver android:name=".files.services.ConnectivityActionReceiver"
|
||||
android:enabled="true" android:label="ConnectivityActionReceiver">
|
||||
<intent-filter>
|
||||
|
|
27
res/drawable-anydpi-v21/arrow_right.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
Copyright (C) 2016 Andy Scherzinger
|
||||
Copyright (C) 2016 Nextcloud.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#ffffff"
|
||||
android:pathData="M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z" />
|
||||
</vector>
|
BIN
res/drawable-hdpi/arrow_right.png
Normal file
After Width: | Height: | Size: 347 B |
BIN
res/drawable-hdpi/ic_done_white.png
Normal file
After Width: | Height: | Size: 188 B |
BIN
res/drawable-hdpi/what_new_instant_upload.png
Normal file
After Width: | Height: | Size: 108 KiB |
BIN
res/drawable-hdpi/whats_new_accounts.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
res/drawable-hdpi/whats_new_files.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
res/drawable-mdpi/arrow_right.png
Normal file
After Width: | Height: | Size: 266 B |
BIN
res/drawable-mdpi/ic_done_white.png
Normal file
After Width: | Height: | Size: 199 B |
BIN
res/drawable-xhdpi/arrow_right.png
Normal file
After Width: | Height: | Size: 357 B |
BIN
res/drawable-xhdpi/ic_done_white.png
Normal file
After Width: | Height: | Size: 199 B |
BIN
res/drawable-xxhdpi/arrow_right.png
Normal file
After Width: | Height: | Size: 497 B |
BIN
res/drawable-xxhdpi/ic_done_white.png
Normal file
After Width: | Height: | Size: 255 B |
BIN
res/drawable-xxxhdpi/arrow_right.png
Normal file
After Width: | Height: | Size: 608 B |
31
res/drawable/indicator_dot_not_selected.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
Copyright (C) 2015-2016 Bartosz Przybylski
|
||||
Copyright (C) 2015 ownCloud Inc.
|
||||
Copyright (C) 2016 Nextcloud.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:bottom="5dp" android:top="5dp" android:right="5dp" android:left="5dp">
|
||||
|
||||
<shape
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/owncloud_blue_dark_transparent"/>
|
||||
<size android:width="8dp" android:height="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
30
res/drawable/indicator_dot_selected.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
Copyright (C) 2015-2016 Bartosz Przybylski
|
||||
Copyright (C) 2015 ownCloud Inc.
|
||||
Copyright (C) 2016 Nextcloud.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:bottom="5dp" android:top="5dp" android:right="5dp" android:left="5dp">
|
||||
<shape
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/white"/>
|
||||
<size android:width="8dp" android:height="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
25
res/drawable/round_button.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
Copyright (C) 2016 Andy Scherzinger
|
||||
Copyright (C) 2015 ownCloud Inc.
|
||||
Copyright (C) 2016 Nextcloud.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/owncloud_blue_accent"/>
|
||||
</shape>
|
24
res/drawable/whats_new_progress_transition.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
Copyright (C) 2015 Bartosz Przybylski
|
||||
Copyright (C) 2016 Nextcloud.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<transition xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/indicator_dot_not_selected" />
|
||||
<item android:drawable="@drawable/indicator_dot_selected" />
|
||||
</transition>
|
90
res/layout/whats_new_activity.xml
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
Copyright (C) 2015-2016 Bartosz Przybylski
|
||||
Copyright (C) 2015 ownCloud Inc.
|
||||
Copyright (C) 2016 Nextcloud.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:weightSum="100">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/welcomeText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_margin="5dp"
|
||||
android:layout_weight="10"
|
||||
android:gravity="center"
|
||||
android:text="@string/placeholder_sentence"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textColor="@color/login_text_hint_color"/>
|
||||
|
||||
<android.support.v4.view.ViewPager
|
||||
android:id="@+id/contentPanel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="80">
|
||||
</android.support.v4.view.ViewPager>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="@dimen/standard_margin"
|
||||
android:layout_marginLeft="@dimen/standard_margin"
|
||||
android:layout_marginRight="@dimen/standard_margin"
|
||||
android:layout_weight="10"
|
||||
android:orientation="horizontal"
|
||||
android:weightSum="3">
|
||||
|
||||
<android.support.v7.widget.AppCompatButton
|
||||
android:id="@+id/skip"
|
||||
style="@style/Button.Borderless.Login"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/whats_new_skip"/>
|
||||
|
||||
<com.owncloud.android.ui.whatsnew.ProgressIndicator
|
||||
android:id="@+id/progressIndicator"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:layout_weight="1">
|
||||
</com.owncloud.android.ui.whatsnew.ProgressIndicator>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/forward"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:padding="@dimen/standard_padding"
|
||||
android:src="@drawable/arrow_right"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
62
res/layout/whats_new_element.xml
Normal file
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Nextcloud Android client application
|
||||
|
||||
Copyright (C) 2015-2016 Bartosz Przybylski
|
||||
Copyright (C) 2015 ownCloud Inc.
|
||||
Copyright (C) 2016 Nextcloud.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:weightSum="100">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:id="@+id/whatsNewImage"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:layout_weight="50"
|
||||
android:src="@drawable/whats_new_files"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NextcloudTextAppearanceHeadline"
|
||||
android:textColor="@color/white"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/welcome_feature_1_title"
|
||||
android:id="@+id/whatsNewTitle"
|
||||
android:layout_margin="@dimen/standard_margin"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/whatsNewText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginBottom="@dimen/standard_margin"
|
||||
android:layout_marginLeft="@dimen/standard_double_margin"
|
||||
android:layout_marginRight="@dimen/standard_double_margin"
|
||||
android:layout_marginTop="@dimen/standard_margin"
|
||||
android:gravity="center"
|
||||
android:text="@string/welcome_feature_1_text"
|
||||
android:textAppearance="@style/NextcloudTextAppearanceMedium"
|
||||
android:textColor="@color/login_text_hint_color"/>
|
||||
</LinearLayout>
|
|
@ -38,6 +38,7 @@
|
|||
<dimen name="standard_half_padding">8dp</dimen>
|
||||
<dimen name="standard_quarter_padding">4dp</dimen>
|
||||
<dimen name="standard_margin">16dp</dimen>
|
||||
<dimen name="standard_double_margin">32dp</dimen>
|
||||
<dimen name="standard_half_margin">8dp</dimen>
|
||||
<dimen name="standard_quarter_margin">4dp</dimen>
|
||||
<dimen name="standard_eighth_margin">2dp</dimen>
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Beta indicator -->
|
||||
<bool name="is_beta">false</bool>
|
||||
|
||||
<!-- App name and other strings-->
|
||||
<string name="app_name">Nextcloud</string>
|
||||
<string name="account_type">nextcloud</string> <!-- better if was a domain name; but changing it now would require migrate accounts when the app is updated -->
|
||||
|
|
|
@ -347,7 +347,7 @@
|
|||
<string name="network_error_socket_timeout_exception">An error occurred while waiting for the server; the operation couldn\'t be completed</string>
|
||||
<string name="network_error_connect_timeout_exception">An error occurred while waiting for the server; the operation couldn\'t be completed</string>
|
||||
<string name="network_host_not_available">The operation couldn\'t be completed; server is unavailable</string>
|
||||
<string name="empty" />
|
||||
<string name="empty" translatable="false" />
|
||||
|
||||
<string name="forbidden_permissions">You do not have permission %s</string>
|
||||
<string name="forbidden_permissions_rename">to rename this file</string>
|
||||
|
@ -545,4 +545,18 @@
|
|||
<string name="storage_description_sd_no">SD card %1$d</string>
|
||||
<string name="storage_description_unknown">Unknown</string>
|
||||
|
||||
<!-- What's new feature and texts to show -->
|
||||
<string name="whats_new_title">What\'s new in Nextcloud</string>
|
||||
|
||||
<!-- Welcome to Nc intro features -->
|
||||
<string name="welcome_feature_1_title">A safe home for all your data</string>
|
||||
<string name="welcome_feature_1_text">Access, share & protect your files at home and in your enterprise</string>
|
||||
|
||||
<string name="welcome_feature_2_title">Multi account</string>
|
||||
<string name="welcome_feature_2_text">Connect to all your clouds</string>
|
||||
|
||||
<string name="welcome_feature_3_title">Instant upload</string>
|
||||
<string name="welcome_feature_3_text">Keep your photos safe</string>
|
||||
|
||||
<string name="whats_new_skip">Skip</string>
|
||||
</resources>
|
||||
|
|
|
@ -113,6 +113,10 @@
|
|||
<item name="android:textColor">@color/color_accent</item>
|
||||
</style>
|
||||
|
||||
<style name="Button.Borderless.Login" parent="Base.Widget.AppCompat.Button.Borderless">
|
||||
<item name="android:textColor">@color/white</item>
|
||||
</style>
|
||||
|
||||
<!-- separat translucent action bar style -->
|
||||
<style name="Theme.ownCloud.Overlay" parent="style/Theme.ownCloud">
|
||||
<item name="android:actionBarStyle">@style/Theme.ownCloud.Overlay.ActionBar</item>
|
||||
|
@ -277,4 +281,14 @@
|
|||
</style>
|
||||
<style name="Theme.ownCloud.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
<style name="Theme.ownCloud.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||
|
||||
<!-- Text styles -->
|
||||
<style name="NextcloudTextAppearanceHeadline" parent="style/TextAppearance.AppCompat.Headline">
|
||||
<item name="android:textSize">26sp</item>
|
||||
<item name="android:textColor">#000000</item>
|
||||
</style>
|
||||
<style name="NextcloudTextAppearanceMedium" parent="style/TextAppearance.AppCompat.Medium">
|
||||
</style>
|
||||
<style name="NextcloudTextAppearanceSmall" parent="style/TextAppearance.AppCompat.Small">
|
||||
</style>
|
||||
</resources>
|
|
@ -41,6 +41,7 @@ import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy;
|
|||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
import com.owncloud.android.services.observer.SyncedFolderObserverService;
|
||||
import com.owncloud.android.ui.activity.Preferences;
|
||||
import com.owncloud.android.ui.activity.WhatsNewActivity;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
||||
|
@ -118,6 +119,7 @@ public class MainApp extends Application {
|
|||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
Log_OC.d(activity.getClass().getSimpleName(), "onCreate(Bundle) starting" );
|
||||
WhatsNewActivity.runIfNeeded(activity);
|
||||
PassCodeManager.getPassCodeManager().onActivityCreated(activity);
|
||||
}
|
||||
|
||||
|
@ -174,6 +176,17 @@ public class MainApp extends Application {
|
|||
return getAppContext().getResources().getString(R.string.account_type);
|
||||
}
|
||||
|
||||
// Non gradle build systems do not provide BuildConfig.VERSION_CODE
|
||||
// so we must fallback to this method :(
|
||||
public static int getVersionCode() {
|
||||
try {
|
||||
String thisPackageName = getAppContext().getPackageName();
|
||||
return getAppContext().getPackageManager().getPackageInfo(thisPackageName, 0).versionCode;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// From AccountAuthenticator
|
||||
// public static final String AUTHORITY = "org.owncloud";
|
||||
public static String getAuthority() {
|
||||
|
|
162
src/com/owncloud/android/features/FeatureList.java
Normal file
|
@ -0,0 +1,162 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Bartosz Przybylski
|
||||
* Copyright (C) 2015 Bartosz Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 Nextcloud.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.features;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.lib.common.utils.Log_OC;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Bartosz Przybylski
|
||||
*/
|
||||
public class FeatureList {
|
||||
private static final boolean SHOW_ON_FIRST_RUN = true;
|
||||
|
||||
private static final String VERSION_1_0_0 = "1.0.0";
|
||||
private static final String BETA_VERSION_0 = "0";
|
||||
|
||||
static final private FeatureItem featuresList[] = {
|
||||
// Basic features showed on first install
|
||||
new FeatureItem(R.drawable.whats_new_files,
|
||||
R.string.welcome_feature_1_title, R.string.welcome_feature_1_text,
|
||||
VERSION_1_0_0, BETA_VERSION_0, SHOW_ON_FIRST_RUN),
|
||||
new FeatureItem(R.drawable.whats_new_accounts,
|
||||
R.string.welcome_feature_2_title, R.string.welcome_feature_2_text,
|
||||
VERSION_1_0_0, BETA_VERSION_0, SHOW_ON_FIRST_RUN),
|
||||
new FeatureItem(R.drawable.what_new_instant_upload,
|
||||
R.string.welcome_feature_3_title, R.string.welcome_feature_3_text,
|
||||
VERSION_1_0_0, BETA_VERSION_0, SHOW_ON_FIRST_RUN),
|
||||
// Features introduced in certain point in time
|
||||
};
|
||||
|
||||
static public FeatureItem[] get() {
|
||||
return featuresList;
|
||||
}
|
||||
|
||||
static public FeatureItem[] getFiltered(final int lastSeenVersionCode, final boolean isFirstRun, boolean isBeta) {
|
||||
List<FeatureItem> features = new LinkedList<>();
|
||||
|
||||
for (FeatureItem item : get()) {
|
||||
final int itemVersionCode = isBeta ? item.getBetaVersionNumber() : item.getVersionNumber();
|
||||
if (isFirstRun && item.shouldShowOnFirstRun()) {
|
||||
features.add(item);
|
||||
} else if (!isFirstRun && !item.shouldShowOnFirstRun() &&
|
||||
MainApp.getVersionCode() >= itemVersionCode &&
|
||||
lastSeenVersionCode < itemVersionCode) {
|
||||
features.add(item);
|
||||
}
|
||||
}
|
||||
return features.toArray(new FeatureItem[features.size()]);
|
||||
}
|
||||
|
||||
static public class FeatureItem implements Parcelable {
|
||||
public static final int DO_NOT_SHOW = -1;
|
||||
private int image;
|
||||
private int titleText;
|
||||
private int contentText;
|
||||
private int versionNumber;
|
||||
private int betaVersion;
|
||||
private boolean showOnInitialRun;
|
||||
|
||||
public FeatureItem(int image, int titleText, int contentText, String version, String betaVersion) {
|
||||
this(image, titleText, contentText, version, betaVersion, false);
|
||||
}
|
||||
|
||||
public FeatureItem(int image, int titleText, int contentText, String version, String betaVersion, boolean showOnInitialRun) {
|
||||
this.image = image;
|
||||
this.titleText = titleText;
|
||||
this.contentText = contentText;
|
||||
this.versionNumber = versionCodeFromString(version);
|
||||
this.betaVersion = Integer.parseInt(betaVersion);
|
||||
this.showOnInitialRun = showOnInitialRun;
|
||||
}
|
||||
|
||||
public boolean shouldShowImage() { return image != DO_NOT_SHOW; }
|
||||
public int getImage() { return image; }
|
||||
|
||||
public boolean shouldShowTitleText() { return titleText != DO_NOT_SHOW; }
|
||||
public int getTitleText() { return titleText; }
|
||||
|
||||
public boolean shouldShowContentText() { return contentText != DO_NOT_SHOW; }
|
||||
public int getContentText() { return contentText; }
|
||||
|
||||
public int getVersionNumber() { return versionNumber; }
|
||||
public int getBetaVersionNumber() { return betaVersion; }
|
||||
public boolean shouldShowOnFirstRun() { return showOnInitialRun; }
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(image);
|
||||
dest.writeInt(titleText);
|
||||
dest.writeInt(contentText);
|
||||
dest.writeInt(versionNumber);
|
||||
dest.writeInt(betaVersion);
|
||||
dest.writeByte((byte) (showOnInitialRun ? 1 : 0));
|
||||
}
|
||||
|
||||
private FeatureItem(Parcel p) {
|
||||
image = p.readInt();
|
||||
titleText = p.readInt();
|
||||
contentText = p.readInt();
|
||||
versionNumber = p.readInt();
|
||||
betaVersion = p.readInt();
|
||||
showOnInitialRun = p.readByte() == 1;
|
||||
}
|
||||
public static final Parcelable.Creator CREATOR =
|
||||
new Parcelable.Creator() {
|
||||
|
||||
@Override
|
||||
public Object createFromParcel(Parcel source) {
|
||||
return new FeatureItem(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] newArray(int size) {
|
||||
return new FeatureItem[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static int versionCodeFromString(String version) {
|
||||
String v[] = version.split(Pattern.quote("."));
|
||||
if (v.length != 3) {
|
||||
Log_OC.e("FeatureList", "Version string is incorrect " + version);
|
||||
return 0;
|
||||
}
|
||||
return Integer.parseInt(v[0])*(int)(10e6) +
|
||||
Integer.parseInt(v[1])*(int)(10e4) +
|
||||
Integer.parseInt(v[2])*100;
|
||||
}
|
||||
}
|
249
src/com/owncloud/android/ui/activity/WhatsNewActivity.java
Normal file
|
@ -0,0 +1,249 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Bartosz Przybylski
|
||||
* Copyright (C) 2015 Bartosz Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 Nextcloud.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.activity;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.owncloud.android.MainApp;
|
||||
import com.owncloud.android.R;
|
||||
import com.owncloud.android.authentication.AccountAuthenticatorActivity;
|
||||
import com.owncloud.android.authentication.AccountUtils;
|
||||
import com.owncloud.android.features.FeatureList;
|
||||
import com.owncloud.android.features.FeatureList.FeatureItem;
|
||||
import com.owncloud.android.ui.whatsnew.ProgressIndicator;
|
||||
|
||||
/**
|
||||
* Activity displaying general feature after a fresh install and new features after an update.
|
||||
*/
|
||||
public class WhatsNewActivity extends FragmentActivity implements ViewPager.OnPageChangeListener {
|
||||
|
||||
private static final String KEY_LAST_SEEN_VERSION_CODE = "lastSeenVersionCode";
|
||||
|
||||
private ImageButton mForwardFinishButton;
|
||||
private Button mSkipButton;
|
||||
private ProgressIndicator mProgress;
|
||||
private ViewPager mPager;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.whats_new_activity);
|
||||
|
||||
mProgress = (ProgressIndicator) findViewById(R.id.progressIndicator);
|
||||
mPager = (ViewPager)findViewById(R.id.contentPanel);
|
||||
final boolean isBeta = getResources().getBoolean(R.bool.is_beta);
|
||||
FeaturesViewAdapter adapter = new FeaturesViewAdapter(getSupportFragmentManager(),
|
||||
FeatureList.getFiltered(getLastSeenVersionCode(), isFirstRun(), isBeta));
|
||||
|
||||
mProgress.setNumberOfSteps(adapter.getCount());
|
||||
mPager.setAdapter(adapter);
|
||||
mPager.addOnPageChangeListener(this);
|
||||
|
||||
|
||||
mForwardFinishButton = (ImageButton) findViewById(R.id.forward);
|
||||
mForwardFinishButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (mProgress.hasNextStep()) {
|
||||
mPager.setCurrentItem(mPager.getCurrentItem()+1, true);
|
||||
mProgress.animateToStep(mPager.getCurrentItem()+1);
|
||||
} else {
|
||||
onFinish();
|
||||
finish();
|
||||
}
|
||||
updateNextButtonIfNeeded();
|
||||
}
|
||||
});
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
mForwardFinishButton.setBackground(null);
|
||||
} else {
|
||||
mForwardFinishButton.setBackgroundDrawable(null);
|
||||
}
|
||||
|
||||
mSkipButton = (Button) findViewById(R.id.skip);
|
||||
mSkipButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
onFinish();
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
TextView tv = (TextView)findViewById(R.id.welcomeText);
|
||||
tv.setText(isFirstRun() ? R.string.empty : R.string.whats_new_title);
|
||||
|
||||
updateNextButtonIfNeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
onFinish();
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
|
||||
private void updateNextButtonIfNeeded() {
|
||||
if (!mProgress.hasNextStep()) {
|
||||
mForwardFinishButton.setImageResource(R.drawable.ic_done_white);
|
||||
mSkipButton.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
mForwardFinishButton.setImageResource(R.drawable.arrow_right);
|
||||
mSkipButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void onFinish() {
|
||||
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
SharedPreferences.Editor editor = pref.edit();
|
||||
editor.putInt(KEY_LAST_SEEN_VERSION_CODE, MainApp.getVersionCode());
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
static private int getLastSeenVersionCode() {
|
||||
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext());
|
||||
return pref.getInt(KEY_LAST_SEEN_VERSION_CODE, 0);
|
||||
}
|
||||
|
||||
static private boolean isFirstRun() {
|
||||
return getLastSeenVersionCode() == 0 && AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext()) == null;
|
||||
}
|
||||
|
||||
static public void runIfNeeded(Context context) {
|
||||
if (context instanceof WhatsNewActivity) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldShow(context)) {
|
||||
context.startActivity(new Intent(context, WhatsNewActivity.class));
|
||||
}
|
||||
}
|
||||
|
||||
static private boolean shouldShow(Context context) {
|
||||
final boolean isBeta = context.getResources().getBoolean(R.bool.is_beta);
|
||||
return (isFirstRun() && context instanceof AccountAuthenticatorActivity) ||
|
||||
(
|
||||
!(isFirstRun() && (context instanceof FileDisplayActivity)) &&
|
||||
!(context instanceof PassCodeActivity) &&
|
||||
(FeatureList.getFiltered(getLastSeenVersionCode(), isFirstRun(), isBeta).length > 0)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
// unused but to be implemented due to abstract parent
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
mProgress.animateToStep(position+1);
|
||||
updateNextButtonIfNeeded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
// unused but to be implemented due to abstract parent
|
||||
}
|
||||
|
||||
private final class FeaturesViewAdapter extends FragmentPagerAdapter {
|
||||
|
||||
private FeatureItem[] mFeatures;
|
||||
|
||||
public FeaturesViewAdapter(FragmentManager fm, FeatureItem[]features) {
|
||||
super(fm);
|
||||
mFeatures = features;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
return FeatureFragment.newInstance(mFeatures[position]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mFeatures.length;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FeatureFragment extends Fragment {
|
||||
private FeatureItem mItem;
|
||||
|
||||
static public FeatureFragment newInstance(FeatureItem item) {
|
||||
FeatureFragment f = new FeatureFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putParcelable("feature", item);
|
||||
f.setArguments(args);
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mItem = getArguments() != null ? (FeatureItem)getArguments().getParcelable("feature") : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.whats_new_element, container, false);
|
||||
|
||||
ImageView iv = (ImageView)v.findViewById(R.id.whatsNewImage);
|
||||
if (mItem.shouldShowImage()) {
|
||||
iv.setImageResource(mItem.getImage());
|
||||
}
|
||||
|
||||
TextView tv2 = (TextView)v.findViewById(R.id.whatsNewTitle);
|
||||
if (mItem.shouldShowTitleText()) {
|
||||
tv2.setText(mItem.getTitleText());
|
||||
}
|
||||
|
||||
tv2 = (TextView)v.findViewById(R.id.whatsNewText);
|
||||
if (mItem.shouldShowContentText()) {
|
||||
tv2.setText(mItem.getContentText());
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
103
src/com/owncloud/android/ui/whatsnew/ProgressIndicator.java
Normal file
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* Nextcloud Android client application
|
||||
*
|
||||
* @author Bartosz Przybylski
|
||||
* Copyright (C) 2015 Bartosz Przybylski
|
||||
* Copyright (C) 2015 ownCloud Inc.
|
||||
* Copyright (C) 2016 Nextcloud.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3 of the License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public
|
||||
* License along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.owncloud.android.ui.whatsnew;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.TransitionDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.owncloud.android.R;
|
||||
|
||||
/**
|
||||
* Progress indicator visualizing the actual progress with dots.
|
||||
*/
|
||||
public class ProgressIndicator extends FrameLayout {
|
||||
|
||||
protected LinearLayout mDotsContainer;
|
||||
|
||||
protected int mNumberOfSteps = -1;
|
||||
protected int mCurrentStep = -1;
|
||||
|
||||
public ProgressIndicator(Context context) {
|
||||
super(context);
|
||||
setup();
|
||||
}
|
||||
|
||||
public ProgressIndicator(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setup();
|
||||
}
|
||||
|
||||
public ProgressIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
setup();
|
||||
}
|
||||
|
||||
public boolean hasNextStep() {
|
||||
return mNumberOfSteps > mCurrentStep;
|
||||
}
|
||||
|
||||
public void setNumberOfSteps(int steps) {
|
||||
mNumberOfSteps = steps;
|
||||
mDotsContainer.removeAllViews();
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
ImageView iv = new ImageView(getContext());
|
||||
iv.setImageDrawable(getContext().getResources().getDrawable(R.drawable.whats_new_progress_transition));
|
||||
mDotsContainer.addView(iv);
|
||||
}
|
||||
animateToStep(1);
|
||||
}
|
||||
|
||||
public void animateToStep(int step) {
|
||||
if (step < 1 || step > mNumberOfSteps) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentStep != -1) {
|
||||
ImageView prevDot = (ImageView) mDotsContainer.getChildAt(mCurrentStep-1);
|
||||
TransitionDrawable transition = (TransitionDrawable)prevDot.getDrawable();
|
||||
transition.resetTransition();
|
||||
}
|
||||
|
||||
mCurrentStep = step;
|
||||
ImageView dot = (ImageView)mDotsContainer.getChildAt(step-1);
|
||||
TransitionDrawable transition = (TransitionDrawable)dot.getDrawable();
|
||||
transition.startTransition(500);
|
||||
}
|
||||
|
||||
private void setup() {
|
||||
mDotsContainer = new LinearLayout(getContext());
|
||||
mDotsContainer.setGravity(Gravity.CENTER);
|
||||
FrameLayout.LayoutParams params = generateDefaultLayoutParams();
|
||||
params.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
params.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
mDotsContainer.setLayoutParams(params);
|
||||
addView(mDotsContainer);
|
||||
}
|
||||
|
||||
}
|