Canteens only for API 21 upwards, show canteen legend, added Rate button, made share button black

This commit is contained in:
Sebastian Seedorf
2019-10-17 22:08:05 +02:00
parent c8dac5d2fc
commit f358bc1fe1
18 changed files with 279 additions and 43 deletions

View File

@@ -69,6 +69,7 @@ import de.sebse.fuplanner.tools.Preferences;
import de.sebse.fuplanner.tools.Regex; import de.sebse.fuplanner.tools.Regex;
import de.sebse.fuplanner.tools.RequestPermissionsResultListener; import de.sebse.fuplanner.tools.RequestPermissionsResultListener;
import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.logging.Logger;
import de.sebse.fuplanner.tools.network.NukeSSLCerts;
import de.sebse.fuplanner.tools.types.News; import de.sebse.fuplanner.tools.types.News;
public class MainActivity extends AppCompatActivity public class MainActivity extends AppCompatActivity

View File

@@ -1,5 +1,6 @@
package de.sebse.fuplanner.fragments; package de.sebse.fuplanner.fragments;
import android.os.Build;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@@ -10,13 +11,15 @@ import de.sebse.fuplanner.R;
import de.sebse.fuplanner.fragments.CanteensFragment.OnCanteensFragmentInteractionListener; import de.sebse.fuplanner.fragments.CanteensFragment.OnCanteensFragmentInteractionListener;
import de.sebse.fuplanner.services.canteen.types.Canteen; import de.sebse.fuplanner.services.canteen.types.Canteen;
import de.sebse.fuplanner.services.canteen.types.Canteens; import de.sebse.fuplanner.services.canteen.types.Canteens;
import de.sebse.fuplanner.tools.ui.CustomViewHolder;
import de.sebse.fuplanner.tools.ui.ItemViewHolder; import de.sebse.fuplanner.tools.ui.ItemViewHolder;
import de.sebse.fuplanner.tools.ui.StringViewHolder;
/** /**
* {@link RecyclerView.Adapter} that can display a {@link Canteen} and makes a call to the * {@link RecyclerView.Adapter} that can display a {@link Canteen} and makes a call to the
* specified {@link OnCanteensFragmentInteractionListener}. * specified {@link OnCanteensFragmentInteractionListener}.
*/ */
class CanteensAdapter extends RecyclerView.Adapter<ItemViewHolder> { class CanteensAdapter extends RecyclerView.Adapter<CustomViewHolder> {
private Canteens mValues; private Canteens mValues;
private final OnCanteensFragmentInteractionListener mListener; private final OnCanteensFragmentInteractionListener mListener;
@@ -33,20 +36,28 @@ class CanteensAdapter extends RecyclerView.Adapter<ItemViewHolder> {
@NonNull @NonNull
@Override @Override
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_all_no_items, parent, false);
return new StringViewHolder(view);
}
View view = LayoutInflater.from(parent.getContext()) View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_all_items, parent, false); .inflate(R.layout.list_all_items, parent, false);
return new ItemViewHolder(view); return new ItemViewHolder(view);
} }
@Override @Override
public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) { public void onBindViewHolder(@NonNull CustomViewHolder holder, int position) {
if (holder instanceof StringViewHolder) {
((StringViewHolder) holder).mString.setText(R.string.canteen_not_available);
} else if (holder instanceof ItemViewHolder) {
if (mValues == null) if (mValues == null)
return; return;
Canteen canteen = mValues.get(holder.getAdapterPosition()); Canteen canteen = mValues.get(holder.getAdapterPosition());
holder.mTitle.setText(canteen.getName()); ((ItemViewHolder) holder).mTitle.setText(canteen.getName());
holder.mSubLeft.setText(canteen.getAddress()); ((ItemViewHolder) holder).mSubLeft.setText(canteen.getAddress());
holder.mSubRight.setText(canteen.getCity()); ((ItemViewHolder) holder).mSubRight.setText(canteen.getCity());
holder.mView.setOnClickListener(v -> { holder.mView.setOnClickListener(v -> {
if (null != mListener) { if (null != mListener) {
@@ -56,9 +67,13 @@ class CanteensAdapter extends RecyclerView.Adapter<ItemViewHolder> {
} }
}); });
} }
}
@Override @Override
public int getItemCount() { public int getItemCount() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
return 1;
}
if (mValues != null) { if (mValues != null) {
return mValues.size(); return mValues.size();
} }

View File

@@ -27,6 +27,10 @@ class MealAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int CATEGORY_OTHER = R.string.others; private final int CATEGORY_OTHER = R.string.others;
private final ArrayList<Object> matches = new ArrayList<>(); private final ArrayList<Object> matches = new ArrayList<>();
private static final int TYPE_MEAL = 0;
private static final int TYPE_HEADER = 1;
private static final int TYPE_LEGEND = 2;
private Day mDay = null; private Day mDay = null;
private final Context mContext; private final Context mContext;
@@ -37,20 +41,25 @@ class MealAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@NonNull @NonNull
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
if (viewType == 0) { if (viewType == TYPE_MEAL) {
View view = LayoutInflater.from(viewGroup.getContext()) View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.list_canteen_items, viewGroup, false); .inflate(R.layout.list_canteen_items, viewGroup, false);
return new MealViewHolder(view); return new MealViewHolder(view);
} else { } else if (viewType == TYPE_HEADER) {
View view = LayoutInflater.from(viewGroup.getContext()) View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.list_all_caption, viewGroup, false); .inflate(R.layout.list_all_caption, viewGroup, false);
return new StringViewHolder(view); return new StringViewHolder(view);
} else {
View view = LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.list_canteen_legend, viewGroup, false);
return new StringViewHolder(view);
} }
} }
@Override @Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if (holder.getItemViewType() == 0) { position = position + 1;
if (holder.getItemViewType() == TYPE_MEAL) {
MealViewHolder viewHolder = ((MealViewHolder) holder); MealViewHolder viewHolder = ((MealViewHolder) holder);
viewHolder.reset(); viewHolder.reset();
Meal meal = getMeal(position); Meal meal = getMeal(position);
@@ -107,7 +116,7 @@ class MealAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
viewHolder.mIconVegetarian.setVisibility(meal.getVegan() == Meal.VEGAN_VEGETARIAN ? View.VISIBLE : View.GONE); viewHolder.mIconVegetarian.setVisibility(meal.getVegan() == Meal.VEGAN_VEGETARIAN ? View.VISIBLE : View.GONE);
viewHolder.mIconBio.setVisibility((meal.getCertificates() & Meal.CERT_BIO) != 0 ? View.VISIBLE : View.GONE); viewHolder.mIconBio.setVisibility((meal.getCertificates() & Meal.CERT_BIO) != 0 ? View.VISIBLE : View.GONE);
viewHolder.mIconMsc.setVisibility((meal.getCertificates() & Meal.CERT_MSC) != 0 ? View.VISIBLE : View.GONE); viewHolder.mIconMsc.setVisibility((meal.getCertificates() & Meal.CERT_MSC) != 0 ? View.VISIBLE : View.GONE);
} else { } else if (holder.getItemViewType() == TYPE_HEADER) {
StringViewHolder viewHolder = ((StringViewHolder) holder); StringViewHolder viewHolder = ((StringViewHolder) holder);
viewHolder.mString.setText(getHeading(position)); viewHolder.mString.setText(getHeading(position));
} }
@@ -115,12 +124,14 @@ class MealAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override @Override
public int getItemCount() { public int getItemCount() {
return matches.size(); return matches.size() + 1;
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
return matches.get(position) instanceof String ? 1 : 0; if (position == 0)
return TYPE_LEGEND;
return matches.get(position + 1) instanceof String ? TYPE_HEADER : TYPE_MEAL;
} }
private Meal getMeal(int position) { private Meal getMeal(int position) {

View File

@@ -1,7 +1,6 @@
package de.sebse.fuplanner.tools.network; package de.sebse.fuplanner.tools.network;
import android.app.Service; import android.app.Service;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
@@ -19,8 +18,6 @@ import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import de.sebse.fuplanner.tools.EventListener; import de.sebse.fuplanner.tools.EventListener;

View File

@@ -0,0 +1,45 @@
package de.sebse.fuplanner.tools.network;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class NukeSSLCerts {
protected static final String TAG = "NukeSSLCerts";
public static void nuke() {
try {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}
}

View File

@@ -0,0 +1,92 @@
package de.sebse.fuplanner.tools.ui;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatTextView;
import de.sebse.fuplanner.R;
public class TextViewDrawableSize extends AppCompatTextView {
private int mDrawableWidth;
private int mDrawableHeight;
public TextViewDrawableSize(Context context) {
super(context);
init(context, null, 0, 0);
}
public TextViewDrawableSize(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs, 0, 0);
}
public TextViewDrawableSize(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr, 0);
}
/*@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public TextViewDrawableSize(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
//super(context, attrs, defStyleAttr, defStyleRes);
//init(context, attrs, defStyleAttr, defStyleRes);
}*/
private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TextViewDrawableSize, defStyleAttr, defStyleRes);
try {
mDrawableWidth = array.getDimensionPixelSize(R.styleable.TextViewDrawableSize_compoundDrawableWidth, -1);
mDrawableHeight = array.getDimensionPixelSize(R.styleable.TextViewDrawableSize_compoundDrawableHeight, -1);
} finally {
array.recycle();
}
if (mDrawableWidth > 0 || mDrawableHeight > 0) {
initCompoundDrawableSize();
}
}
private void initCompoundDrawableSize() {
Drawable[] drawables = getCompoundDrawables();
for (Drawable drawable : drawables) {
if (drawable == null) {
continue;
}
Rect realBounds = drawable.getBounds();
float scaleFactor = realBounds.height() / (float) realBounds.width();
float drawableWidth = realBounds.width();
float drawableHeight = realBounds.height();
if (mDrawableWidth > 0) {
// save scale factor of image
if (drawableWidth > mDrawableWidth) {
drawableWidth = mDrawableWidth;
drawableHeight = drawableWidth * scaleFactor;
}
}
if (mDrawableHeight > 0) {
// save scale factor of image
if (drawableHeight > mDrawableHeight) {
drawableHeight = mDrawableHeight;
drawableWidth = drawableHeight / scaleFactor;
}
}
realBounds.right = realBounds.left + Math.round(drawableWidth);
realBounds.bottom = realBounds.top + Math.round(drawableHeight);
drawable.setBounds(realBounds);
}
setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);
}
}

View File

@@ -1,8 +1,8 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:viewportWidth="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FF000000" android:fillColor="#FF000000"
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/> android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>

View File

@@ -5,6 +5,7 @@
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/string"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin" android:layout_margin="@dimen/text_margin"

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:columnCount="2">
<de.sebse.fuplanner.tools.ui.TextViewDrawableSize
android:layout_columnWeight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/vegetarian"
android:drawableStart="@mipmap/ic_vegetarian"
android:drawableLeft="@mipmap/ic_vegetarian"
android:gravity="center_vertical"
app:compoundDrawableHeight="16dp"
app:compoundDrawableWidth="16dp" />
<de.sebse.fuplanner.tools.ui.TextViewDrawableSize
android:layout_columnWeight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/vegan"
android:drawableStart="@mipmap/ic_vegan"
android:drawableLeft="@mipmap/ic_vegan"
android:gravity="center_vertical"
app:compoundDrawableHeight="16dp"
app:compoundDrawableWidth="16dp" />
<de.sebse.fuplanner.tools.ui.TextViewDrawableSize
android:layout_columnWeight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/msc"
android:drawableStart="@mipmap/ic_msc"
android:drawableLeft="@mipmap/ic_msc"
android:gravity="center_vertical"
app:compoundDrawableHeight="16dp"
app:compoundDrawableWidth="16dp" />
<de.sebse.fuplanner.tools.ui.TextViewDrawableSize
android:layout_columnWeight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/bio"
android:drawableStart="@mipmap/ic_organic"
android:drawableLeft="@mipmap/ic_organic"
android:gravity="center_vertical"
app:compoundDrawableHeight="16dp"
app:compoundDrawableWidth="16dp" />
</GridLayout>

View File

@@ -19,7 +19,7 @@
<menu> <menu>
<item <item
android:id="@+id/nav_share" android:id="@+id/nav_share"
android:icon="@drawable/ic_menu_share" android:icon="@drawable/ic_share"
android:title="@string/share" android:title="@string/share"
android:orderInCategory="700"/> android:orderInCategory="700"/>
<item <item

View File

@@ -39,7 +39,7 @@
android:orderInCategory="600"/> android:orderInCategory="600"/>
<item <item
android:id="@+id/nav_share" android:id="@+id/nav_share"
android:icon="@drawable/ic_menu_share" android:icon="@drawable/ic_share"
android:title="@string/share" android:title="@string/share"
android:orderInCategory="700"/> android:orderInCategory="700"/>
<item <item

View File

@@ -86,7 +86,6 @@
<string name="tricks">Tipps/Tricks</string> <string name="tricks">Tipps/Tricks</string>
<string name="back_to_exit">Klicke ZURÜCK erneut zum Beenden!</string> <string name="back_to_exit">Klicke ZURÜCK erneut zum Beenden!</string>
<string name="title_activity_fuauthenticator">Sign in</string> <string name="title_activity_fuauthenticator">Sign in</string>
<!-- Strings related to login -->
<string name="prompt_email">Benutzername</string> <string name="prompt_email">Benutzername</string>
<string name="prompt_password">Passwort (optional)</string> <string name="prompt_password">Passwort (optional)</string>
<string name="action_sign_in">Log in</string> <string name="action_sign_in">Log in</string>
@@ -115,4 +114,5 @@
<string name="network_error">Ein Netzwerkfehler ist aufgetreten!</string> <string name="network_error">Ein Netzwerkfehler ist aufgetreten!</string>
<string name="network_error_parameter">Ein Netzwerkfehler ist aufgetreten: %s!</string> <string name="network_error_parameter">Ein Netzwerkfehler ist aufgetreten: %s!</string>
<string name="rate_the_app">App bewerten!</string> <string name="rate_the_app">App bewerten!</string>
<string name="canteen_not_available">Die Kantinenliste ist für Android 4 und darunter nicht verfügbar!</string>
</resources> </resources>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ExpandableCardView">
<attr name="outer_view" format="reference"/>
<attr name="inner_view" format="reference"/>
<attr name="animationDuration" format="integer"/>
<attr name="startExpanded" format="boolean"/>
</declare-styleable>
</resources>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="TextViewDrawableSize">
<attr name="compoundDrawableWidth" format="dimension"/>
<attr name="compoundDrawableHeight" format="dimension"/>
</declare-styleable>
</resources>

View File

@@ -62,10 +62,4 @@
<attr name="dropListenerEnabled" format="boolean" /> <attr name="dropListenerEnabled" format="boolean" />
<attr name="defaultEventColor" format="color" /> <attr name="defaultEventColor" format="color" />
</declare-styleable> </declare-styleable>
<declare-styleable name="ExpandableCardView">
<attr name="outer_view" format="reference"/>
<attr name="inner_view" format="reference"/>
<attr name="animationDuration" format="integer"/>
<attr name="startExpanded" format="boolean"/>
</declare-styleable>
</resources> </resources>

View File

@@ -1,3 +0,0 @@
<resources>
<item name="ic_menu_share" type="drawable">@android:drawable/ic_menu_share</item>
</resources>

View File

@@ -94,7 +94,6 @@
<string name="tricks">Tips/Tricks</string> <string name="tricks">Tips/Tricks</string>
<string name="back_to_exit">Please click BACK again to exit!</string> <string name="back_to_exit">Please click BACK again to exit!</string>
<string name="title_activity_fuauthenticator">Sign in</string> <string name="title_activity_fuauthenticator">Sign in</string>
<!-- Strings related to login -->
<string name="prompt_email">Username</string> <string name="prompt_email">Username</string>
<string name="prompt_password">Password (optional)</string> <string name="prompt_password">Password (optional)</string>
<string name="action_sign_in">Sign in or register</string> <string name="action_sign_in">Sign in or register</string>
@@ -123,4 +122,5 @@
<string name="network_error">A network error occurred!</string> <string name="network_error">A network error occurred!</string>
<string name="network_error_parameter">A network error occurred: %s!</string> <string name="network_error_parameter">A network error occurred: %s!</string>
<string name="rate_the_app">Rate the App!</string> <string name="rate_the_app">Rate the App!</string>
<string name="canteen_not_available">The canteen list is not available for Android 4 and below!</string>
</resources> </resources>

19
fuplanner.iml Normal file
View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="fuplanner" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>