@Override
  public final void prepare(final Context context, final LinearLayout items) {

    final LoadingView loadingView = new LoadingView(context, R.string.download_waiting, true, true);
    items.addView(loadingView);

    username = getArguments().getString("user");
    final CacheManager cm = CacheManager.getInstance(context);

    RedditAPI.getUser(
        cm,
        username,
        new APIResponseHandler.UserResponseHandler(context) {
          @Override
          protected void onDownloadStarted() {
            if (!active) return;
            loadingView.setIndeterminate(R.string.download_connecting);
          }

          @Override
          protected void onSuccess(final RedditUser user, long timestamp) {

            new Handler(Looper.getMainLooper())
                .post(
                    new Runnable() {
                      public void run() {

                        if (!active) return;

                        loadingView.setDone(R.string.download_done);

                        final LinearLayout karmaLayout =
                            (LinearLayout) getLayoutInflater().inflate(R.layout.karma);
                        items.addView(karmaLayout);

                        final TextView linkKarma =
                            (TextView) karmaLayout.findViewById(R.id.layout_karma_text_link);
                        final TextView commentKarma =
                            (TextView) karmaLayout.findViewById(R.id.layout_karma_text_comment);

                        linkKarma.setText(String.valueOf(user.link_karma));
                        commentKarma.setText(String.valueOf(user.comment_karma));

                        items.addView(
                            propView(
                                context,
                                R.string.userprofile_created,
                                RRTime.formatDateTime(user.created_utc * 1000, context),
                                false));

                        if (user.has_mail != null) {
                          items.addView(
                              propView(
                                  context,
                                  R.string.userprofile_hasmail,
                                  user.has_mail ? R.string.general_true : R.string.general_false,
                                  false));
                        }

                        if (user.has_mod_mail != null) {
                          items.addView(
                              propView(
                                  context,
                                  R.string.userprofile_hasmodmail,
                                  user.has_mod_mail
                                      ? R.string.general_true
                                      : R.string.general_false,
                                  false));
                        }

                        if (user.is_friend) {
                          items.addView(
                              propView(
                                  context,
                                  R.string.userprofile_isfriend,
                                  R.string.general_true,
                                  false));
                        }

                        if (user.is_gold) {
                          items.addView(
                              propView(
                                  context,
                                  R.string.userprofile_isgold,
                                  R.string.general_true,
                                  false));
                        }

                        if (user.is_mod) {
                          items.addView(
                              propView(
                                  context,
                                  R.string.userprofile_moderator,
                                  R.string.general_true,
                                  false));
                        }

                        final Button commentsButton = new Button(context);
                        commentsButton.setText(R.string.userprofile_viewcomments);
                        commentsButton.setOnClickListener(
                            new View.OnClickListener() {
                              public void onClick(View v) {
                                final Intent intent =
                                    new Intent(context, CommentListingActivity.class);
                                intent.setData(
                                    Uri.parse(
                                        Constants.Reddit.getUri(
                                                "/user/" + username + "/comments.json")
                                            .toString()));
                                startActivity(intent);
                                dismiss();
                              }
                            });
                        items.addView(commentsButton);
                        // TODO use margin? or framelayout? scale padding dp
                        // TODO change button color
                        commentsButton.setPadding(20, 20, 20, 20);

                        final Button postsButton = new Button(context);
                        postsButton.setText(R.string.userprofile_viewposts);
                        postsButton.setOnClickListener(
                            new View.OnClickListener() {
                              public void onClick(View v) {
                                final Intent intent =
                                    new Intent(context, PostListingActivity.class);
                                intent.putExtra(
                                    "subreddit",
                                    new RedditSubreddit(
                                        "/user/" + username + "/submitted",
                                        "Submitted by " + username,
                                        false));
                                startActivity(intent);
                                dismiss();
                              }
                            });
                        items.addView(postsButton);
                        // TODO use margin? or framelayout? scale padding dp
                        postsButton.setPadding(20, 20, 20, 20);
                      }
                    });
          }

          @Override
          protected void onCallbackException(Throwable t) {
            BugReportActivity.handleGlobalError(context, t);
          }

          @Override
          protected void onFailure(
              final RequestFailureType type,
              final Throwable t,
              final StatusLine status,
              final String readableMessage) {

            new Handler(Looper.getMainLooper())
                .post(
                    new Runnable() {
                      public void run() {

                        if (!active) return;

                        loadingView.setDone(R.string.download_failed);

                        final RRError error =
                            General.getGeneralErrorForFailure(context, type, t, status);
                        items.addView(new ErrorView(getSupportActivity(), error));
                      }
                    });
          }

          @Override
          protected void onFailure(final APIFailureType type) {

            new Handler(Looper.getMainLooper())
                .post(
                    new Runnable() {
                      public void run() {

                        if (!active) return;

                        loadingView.setDone(R.string.download_failed);

                        final RRError error = General.getGeneralErrorForFailure(context, type);
                        items.addView(new ErrorView(getSupportActivity(), error));
                      }
                    });
          }
        },
        RedditAccountManager.getInstance(context).getDefaultAccount(),
        CacheRequest.DownloadType.FORCE,
        true,
        context);
  }
  public void reset(final int listPosition, final ImageInfo info) {

    mImageInfo = info;

    if (info.title == null || info.title.trim().isEmpty()) {
      mTitle.setText("Image " + (listPosition + 1));
    } else {
      mTitle.setText((listPosition + 1) + ". " + info.title.trim());
    }

    String subtitle = "";

    if (info.type != null) {
      subtitle += info.type;
    }

    if (info.width != null && info.height != null) {

      if (!subtitle.isEmpty()) subtitle += ", ";

      subtitle += info.width + "x" + info.height;
    }

    if (info.size != null) {

      if (!subtitle.isEmpty()) subtitle += ", ";

      long size = info.size;

      if (size < 512 * 1024) {
        subtitle += String.format("%.1f kB", (float) size / 1024);
      } else {
        subtitle += String.format("%.1f MB", (float) size / (1024 * 1024));
      }
    }

    if (subtitle.isEmpty()) {
      mSubtitle.setVisibility(GONE);
    } else {
      mSubtitle.setVisibility(VISIBLE);
    }

    mSubtitle.setText(subtitle);

    mThumbnail.setImageBitmap(null);

    final boolean isConnectionWifi = General.isConnectionWifi(getContext());

    final PrefsUtility.AppearanceThumbnailsShow thumbnailsPref =
        PrefsUtility.appearance_thumbnails_show(
            getContext(), PreferenceManager.getDefaultSharedPreferences(getContext()));

    final boolean downloadThumbnails =
        thumbnailsPref == PrefsUtility.AppearanceThumbnailsShow.ALWAYS
            || (thumbnailsPref == PrefsUtility.AppearanceThumbnailsShow.WIFIONLY
                && isConnectionWifi);

    if (!downloadThumbnails) {
      mThumbnail.setVisibility(GONE);

    } else {

      mThumbnail.setVisibility(VISIBLE);

      CacheManager.getInstance(getContext())
          .makeRequest(
              new CacheRequest(
                  General.uriFromString(info.urlBigSquare),
                  RedditAccountManager.getAnon(),
                  null,
                  Constants.Priority.THUMBNAIL,
                  listPosition,
                  CacheRequest.DownloadType.IF_NECESSARY,
                  Constants.FileType.THUMBNAIL,
                  CacheRequest.DownloadQueueType.IMMEDIATE,
                  false,
                  false,
                  getContext()) {
                @Override
                protected void onCallbackException(final Throwable t) {
                  Log.e("ImgurAlbumListEntryView", "Error in album thumbnail fetch callback", t);
                }

                @Override
                protected void onDownloadNecessary() {}

                @Override
                protected void onDownloadStarted() {}

                @Override
                protected void onFailure(
                    final RequestFailureType type,
                    final Throwable t,
                    final Integer status,
                    final String readableMessage) {
                  Log.e("ImgurAlbumListEntryView", "Failed to fetch thumbnail " + url.toString());
                }

                @Override
                protected void onProgress(
                    final boolean authorizationInProgress,
                    final long bytesRead,
                    final long totalBytes) {}

                @Override
                protected void onSuccess(
                    final CacheManager.ReadableCacheFile cacheFile,
                    final long timestamp,
                    final UUID session,
                    final boolean fromCache,
                    final String mimetype) {

                  if (mImageInfo != info) return;

                  // TODO post message rather than runnable
                  AndroidApi.UI_THREAD_HANDLER.post(
                      new Runnable() {
                        @Override
                        public void run() {
                          try {
                            mThumbnail.setImageURI(cacheFile.getUri());
                          } catch (IOException e) {
                            throw new RuntimeException(e);
                          }
                        }
                      });
                }
              });
    }
  }
  @Override
  public boolean onOptionsItemSelected(final MenuItem item) {
    switch (item.getItemId()) {
      case OPTIONS_MENU_MARK_ALL_AS_READ:
        RedditAPI.markAllAsRead(
            CacheManager.getInstance(this),
            new APIResponseHandler.ActionResponseHandler(this) {
              @Override
              protected void onSuccess() {
                General.quickToast(context, R.string.mark_all_as_read_success);
              }

              @Override
              protected void onCallbackException(final Throwable t) {
                BugReportActivity.addGlobalError(
                    new RRError("Mark all as Read failed", "Callback exception", t));
              }

              @Override
              protected void onFailure(
                  final @CacheRequest.RequestFailureType int type,
                  final Throwable t,
                  final Integer status,
                  final String readableMessage) {
                final RRError error =
                    General.getGeneralErrorForFailure(
                        context, type, t, status, "Reddit API action: Mark all as Read");
                AndroidApi.UI_THREAD_HANDLER.post(
                    new Runnable() {
                      public void run() {
                        General.showResultDialog(InboxListingActivity.this, error);
                      }
                    });
              }

              @Override
              protected void onFailure(final APIFailureType type) {

                final RRError error = General.getGeneralErrorForFailure(context, type);
                AndroidApi.UI_THREAD_HANDLER.post(
                    new Runnable() {
                      public void run() {
                        General.showResultDialog(InboxListingActivity.this, error);
                      }
                    });
              }
            },
            RedditAccountManager.getInstance(this).getDefaultAccount(),
            this);

        return true;
      case OPTIONS_MENU_SHOW_UNREAD_ONLY:
        if (!item.isChecked()) {
          item.setChecked(true);
          editor.putBoolean("onlyUnread", true);
          onlyUnread = true;
        } else {
          item.setChecked(false);
          editor.putBoolean("onlyUnread", false);
          onlyUnread = false;
        }
        editor.commit();
        makeFirstRequest(this);
        return true;
      case android.R.id.home:
        finish();
        return true;
      default:
        return super.onOptionsItemSelected(item);
    }
  }
  private void makeFirstRequest(final Context context) {

    final RedditAccount user = RedditAccountManager.getInstance(context).getDefaultAccount();
    final CacheManager cm = CacheManager.getInstance(context);

    final URI url;

    if (!isModmail) {
      if (onlyUnread) {
        url = Constants.Reddit.getUri("/message/unread.json?mark=true&limit=100");
      } else {
        url = Constants.Reddit.getUri("/message/inbox.json?mark=true&limit=100");
      }
    } else {
      url = Constants.Reddit.getUri("/message/moderator.json?limit=100");
    }

    // TODO parameterise limit
    request =
        new CacheRequest(
            url,
            user,
            null,
            Constants.Priority.API_INBOX_LIST,
            0,
            CacheRequest.DOWNLOAD_FORCE,
            Constants.FileType.INBOX_LIST,
            CacheRequest.DOWNLOAD_QUEUE_REDDIT_API,
            true,
            true,
            context) {

          @Override
          protected void onDownloadNecessary() {}

          @Override
          protected void onDownloadStarted() {}

          @Override
          protected void onCallbackException(final Throwable t) {
            request = null;
            BugReportActivity.handleGlobalError(context, t);
          }

          @Override
          protected void onFailure(
              final @CacheRequest.RequestFailureType int type,
              final Throwable t,
              final Integer status,
              final String readableMessage) {

            request = null;

            if (loadingView != null) loadingView.setDone(R.string.download_failed);

            final RRError error =
                General.getGeneralErrorForFailure(context, type, t, status, url.toString());
            AndroidApi.UI_THREAD_HANDLER.post(
                new Runnable() {
                  public void run() {
                    notifications.addView(new ErrorView(InboxListingActivity.this, error));
                  }
                });

            if (t != null) t.printStackTrace();
          }

          @Override
          protected void onProgress(
              final boolean authorizationInProgress, final long bytesRead, final long totalBytes) {}

          @Override
          protected void onSuccess(
              final CacheManager.ReadableCacheFile cacheFile,
              final long timestamp,
              final UUID session,
              final boolean fromCache,
              final String mimetype) {
            request = null;
          }

          @Override
          public void onJsonParseStarted(
              final JsonValue value,
              final long timestamp,
              final UUID session,
              final boolean fromCache) {

            if (loadingView != null) loadingView.setIndeterminate(R.string.download_downloading);

            // TODO pref (currently 10 mins)
            // TODO xml
            if (fromCache && RRTime.since(timestamp) > 10 * 60 * 1000) {
              AndroidApi.UI_THREAD_HANDLER.post(
                  new Runnable() {
                    public void run() {
                      final TextView cacheNotif = new TextView(context);
                      cacheNotif.setText(
                          context.getString(R.string.listing_cached)
                              + RRTime.formatDateTime(timestamp, context));
                      final int paddingPx = General.dpToPixels(context, 6);
                      final int sidePaddingPx = General.dpToPixels(context, 10);
                      cacheNotif.setPadding(sidePaddingPx, paddingPx, sidePaddingPx, paddingPx);
                      cacheNotif.setTextSize(13f);
                      notifications.addView(cacheNotif);
                      adapter.notifyDataSetChanged();
                    }
                  });
            }

            // TODO {"error": 403} is received for unauthorized subreddits

            try {
              final JsonBufferedObject root = value.asObject();
              final JsonBufferedObject data = root.getObject("data");
              final JsonBufferedArray children = data.getArray("children");

              for (JsonValue child : children) {

                final RedditThing thing = child.asObject(RedditThing.class);

                switch (thing.getKind()) {
                  case COMMENT:
                    final RedditComment comment = thing.asComment();
                    final RedditParsedComment parsedComment = new RedditParsedComment(comment);
                    final RedditRenderableComment renderableComment =
                        new RedditRenderableComment(parsedComment, null, -100000, false);
                    itemHandler.sendMessage(General.handlerMessage(0, renderableComment));

                    break;

                  case MESSAGE:
                    final RedditPreparedMessage message =
                        new RedditPreparedMessage(
                            InboxListingActivity.this, thing.asMessage(), timestamp);
                    itemHandler.sendMessage(General.handlerMessage(0, message));

                    if (message.src.replies != null
                        && message.src.replies.getType() == JsonValue.TYPE_OBJECT) {

                      final JsonBufferedArray replies =
                          message.src.replies.asObject().getObject("data").getArray("children");

                      for (JsonValue childMsgValue : replies) {
                        final RedditMessage childMsgRaw =
                            childMsgValue.asObject(RedditThing.class).asMessage();
                        final RedditPreparedMessage childMsg =
                            new RedditPreparedMessage(
                                InboxListingActivity.this, childMsgRaw, timestamp);
                        itemHandler.sendMessage(General.handlerMessage(0, childMsg));
                      }
                    }

                    break;

                  default:
                    throw new RuntimeException("Unknown item in list.");
                }
              }

            } catch (Throwable t) {
              notifyFailure(CacheRequest.REQUEST_FAILURE_PARSE, t, null, "Parse failure");
              return;
            }

            if (loadingView != null) loadingView.setDone(R.string.download_done);
          }
        };

    cm.makeRequest(request);
  }
Beispiel #5
0
  @Override
  public void onCreate() {

    super.onCreate();

    Log.i("RedReader", "Application created.");

    final Thread.UncaughtExceptionHandler androidHandler =
        Thread.getDefaultUncaughtExceptionHandler();

    Thread.setDefaultUncaughtExceptionHandler(
        new Thread.UncaughtExceptionHandler() {
          public void uncaughtException(Thread thread, Throwable t) {

            try {
              t.printStackTrace();

              File dir = Environment.getExternalStorageDirectory();

              if (dir == null) {
                dir = Environment.getDataDirectory();
              }

              final FileOutputStream fos =
                  new FileOutputStream(
                      new File(
                          dir, "redreader_crash_log_" + UUID.randomUUID().toString() + ".txt"));
              final PrintWriter pw = new PrintWriter(fos);
              t.printStackTrace(pw);
              pw.flush();
              pw.close();

            } catch (Throwable t1) {
            }

            androidHandler.uncaughtException(thread, t);
          }
        });

    final CacheManager cm = CacheManager.getInstance(this);

    cm.pruneTemp();

    new Thread() {
      @Override
      public void run() {

        android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);

        cm.pruneCache(); // Hope for the best :)
      }
    }.start();

    new Thread() {
      @Override
      public void run() {
        RedditChangeDataIO.getInstance(RedReader.this).runInitialReadInThisThread();
        RedditChangeDataManager.pruneAllUsers();
      }
    }.start();

    Alarms.onBoot(this);

    NewMessageChecker.checkForNewMessages(this);
  }
  @Override
  protected void onCreate(Bundle savedInstanceState) {

    PrefsUtility.applyTheme(this);
    getSupportActionBar().setTitle(R.string.post_captcha_title);

    super.onCreate(savedInstanceState);

    final LoadingView loadingView = new LoadingView(this, R.string.download_waiting, true, true);
    setContentView(loadingView);

    final RedditAccount selectedAccount =
        RedditAccountManager.getInstance(this).getAccount(getIntent().getStringExtra("username"));

    final CacheManager cm = CacheManager.getInstance(this);

    RedditAPI.newCaptcha(
        cm,
        new APIResponseHandler.NewCaptchaResponseHandler(this) {
          @Override
          protected void onSuccess(final String captchaId) {

            final URI captchaUrl = Constants.Reddit.getUri("/captcha/" + captchaId);

            cm.makeRequest(
                new CacheRequest(
                    captchaUrl,
                    RedditAccountManager.getAnon(),
                    null,
                    Constants.Priority.CAPTCHA,
                    0,
                    CacheRequest.DownloadType.FORCE,
                    Constants.FileType.CAPTCHA,
                    false,
                    false,
                    true,
                    CaptchaActivity.this) {
                  @Override
                  protected void onCallbackException(Throwable t) {
                    BugReportActivity.handleGlobalError(CaptchaActivity.this, t);
                  }

                  @Override
                  protected void onDownloadNecessary() {}

                  @Override
                  protected void onDownloadStarted() {
                    loadingView.setIndeterminate(R.string.download_downloading);
                  }

                  @Override
                  protected void onFailure(
                      RequestFailureType type,
                      Throwable t,
                      StatusLine status,
                      String readableMessage) {
                    final RRError error =
                        General.getGeneralErrorForFailure(
                            CaptchaActivity.this, type, t, status, url.toString());
                    General.showResultDialog(CaptchaActivity.this, error);
                    finish();
                  }

                  @Override
                  protected void onProgress(long bytesRead, long totalBytes) {
                    loadingView.setProgress(
                        R.string.download_downloading,
                        (float) ((double) bytesRead / (double) totalBytes));
                  }

                  @Override
                  protected void onSuccess(
                      final CacheManager.ReadableCacheFile cacheFile,
                      long timestamp,
                      UUID session,
                      boolean fromCache,
                      String mimetype) {

                    final Bitmap image;
                    try {
                      image = BitmapFactory.decodeStream(cacheFile.getInputStream());
                    } catch (IOException e) {
                      BugReportActivity.handleGlobalError(CaptchaActivity.this, e);
                      return;
                    }

                    new Handler(Looper.getMainLooper())
                        .post(
                            new Runnable() {
                              public void run() {

                                final LinearLayout ll = new LinearLayout(CaptchaActivity.this);
                                ll.setOrientation(LinearLayout.VERTICAL);

                                final ImageView captchaImg = new ImageView(CaptchaActivity.this);
                                ll.addView(captchaImg);
                                final LinearLayout.LayoutParams layoutParams =
                                    (LinearLayout.LayoutParams) captchaImg.getLayoutParams();
                                layoutParams.setMargins(20, 20, 20, 20);
                                layoutParams.height = General.dpToPixels(context, 100);
                                captchaImg.setScaleType(ImageView.ScaleType.FIT_CENTER);

                                final EditText captchaText = new EditText(CaptchaActivity.this);
                                ll.addView(captchaText);
                                ((LinearLayout.LayoutParams) captchaText.getLayoutParams())
                                    .setMargins(20, 0, 20, 20);
                                captchaText.setInputType(
                                    android.text.InputType.TYPE_CLASS_TEXT
                                        | android.text.InputType
                                            .TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
                                        | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS);

                                captchaImg.setImageBitmap(image);

                                final Button submitButton = new Button(CaptchaActivity.this);
                                submitButton.setText(R.string.post_captcha_submit_button);
                                ll.addView(submitButton);
                                ((LinearLayout.LayoutParams) submitButton.getLayoutParams())
                                    .setMargins(20, 0, 20, 20);
                                ((LinearLayout.LayoutParams) submitButton.getLayoutParams())
                                        .gravity =
                                    Gravity.RIGHT;
                                ((LinearLayout.LayoutParams) submitButton.getLayoutParams()).width =
                                    LinearLayout.LayoutParams.WRAP_CONTENT;

                                submitButton.setOnClickListener(
                                    new View.OnClickListener() {
                                      public void onClick(View v) {
                                        final Intent result = new Intent();
                                        result.putExtra("captchaId", captchaId);
                                        result.putExtra(
                                            "captchaText", captchaText.getText().toString());
                                        setResult(RESULT_OK, result);
                                        finish();
                                      }
                                    });

                                final ScrollView sv = new ScrollView(CaptchaActivity.this);
                                sv.addView(ll);
                                setContentView(sv);
                              }
                            });
                  }
                });
          }

          @Override
          protected void onCallbackException(Throwable t) {
            BugReportActivity.handleGlobalError(CaptchaActivity.this, t);
          }

          @Override
          protected void onFailure(
              RequestFailureType type, Throwable t, StatusLine status, String readableMessage) {
            final RRError error =
                General.getGeneralErrorForFailure(CaptchaActivity.this, type, t, status, null);
            General.showResultDialog(CaptchaActivity.this, error);
            finish();
          }

          @Override
          protected void onFailure(APIFailureType type) {
            final RRError error = General.getGeneralErrorForFailure(CaptchaActivity.this, type);
            General.showResultDialog(CaptchaActivity.this, error);
            finish();
          }
        },
        selectedAccount,
        this);
  }